C中的文件指针,如何测量当前位置到文件末尾的距离?
For a file pointer in C, how to measure the distance between the current position to the end of file?
对于给定的文件指针(FILE *
),是否可以快速确定从当前位置到文件末尾的距离。
计算实际距离所需的时间应该与距离无关。
比如fpos_t
的减法,但是fpos_t不是整数,不能进行数值运算。还有其他方法吗?
For example the subtraction of fpos_t, but fpos_t is not integer, it cannot be operated numerically. Is there any alternative way?
不,你不能。
FILE 结构不知道文件有多长,因此没有简单的方法来找到这个距离。该文件被视为一条道路 - 您转入道路并沿着道路行驶,当道路结束时,您会发现。但是没有标志告诉你路有多长。
您可以单独询问 OS,使用 stat
或类似的。但请注意,FILE 甚至并不总是引用具有已定义结尾的文件 - 它可能 stdin
来自管道,并且当时大小完全未知。
当你第一次打开文件时,你可以使用fseek()
转到文件末尾(但请参阅下面的注释),然后使用ftell()
获取位置并保存(作为文件的大小)。然后调用rewind()
回到开头。
然后,可以从保存的 'size' 中减去以后调用 ftell()
的 return 值,以获得从当前位置到文件末尾的偏移量(距离) :
// Given a FILE* fp that's just been opened:
fseek(fp, 0, SEEK_END);
long int endpos = ftell(fp);
rewind(fp); // Or you can use fseek(fp, 0, SEEK_SET);
//...
// Later in your code:
long int dtoend = endpos - ftell(pf);
但请注意,实现 不需要 来实现 SEEK_END
:来自上面链接的 fseek
上的 cplusplus.com 页面:
- Library implementations are allowed to not meaningfully support SEEK_END (therefore, code using it has no real standard portability).
澄清一下(根据一些评论):上面的代码 要求 endpos
值在文件 open/read 操作。一个 可以 通过寻找结束然后在任何时候恢复 当前 位置来避免这种情况,但效率会低得多。例如,可以编写一个函数来随时获取到终点的距离:
long int dtoend(FILE *fp)
{
long int curpos = ftell(fp); // Get current position
fseek(fp, 0, SEEK_END); // Go to the file's end
long endpos = ftell(fp); // Gets the file's size
fseek(fp, curpos, SEEK_SET); // Restore previous pos
return endpos - curpos; // Return the distance!
}
使用大型(> 2GB)文件的注意事项:以上代码使用标准 fseek
和 ftell
函数,它们使用 long int
类型(即通常为 32 位宽)用于文件位置;要对较大的文件使用类似的代码,有许多(尽管是特定于平台的)替代方案...
在 Windows 平台上,使用 MSVC
(或兼容)编译器,有 _ftelli64
and _fseeki64
函数,它们的使用方式几乎与它们的 'standard'同行;例如,通过对上述代码进行以下更改:
//...
int64_t curpos = _ftelli64(fp); // Get current position
_fseeki64(fp, 0LL, SEEK_END); // Go to the file's end
//... and similar changes elsewhere
在 Linux 系统上,如果您 确保 ,则 64 位调用将实现为 ftello
and fseeko
至 #define _FILE_OFFSET_BITS 64
.
其他 platforms/compilers 可能会实现上述任一(或两者),或者有一些其他非常相似的 64 位替代品。
注释 #2 - 错误处理: 正如评论中所指出的,使用 SEEK_END
作为 origin 参数调用 fseek
可能会在多种不同情况下失败;例如,如果文件指针是 stdin
,如果它指的是管道流,或者(在某些系统上)如果文件以 文本模式 [=78= 打开]†。要处理这种情况,应该真正检查 fseek
调用的 return 值,如果失败,它将是 非零 。因此,这里是实现了此类错误处理的 dtoend
函数的 64 位版本(请注意 MSVC
或 GNU
以外的编译器,您需要添加相关的定义宏bigseek
和 bigtell
函数):
#include <stdio.h>
#include <stdint.h>
#if defined (_MSC_VER) // MSVC/Windows...
#define bigtell _ftelli64
#define bigseek _fseeki64
#elif defined (__GNUC__) // GNU/Linux...
#define _FILE_OFFSET_BITS 64
#define bigtell ftello
#define bigseek fseeko
//
// Feel free to add other compiler/platform implementations
//
#else // Unknown platform/compiler - likely to cause warnings!
#define bigtell ftell
#define bigseek fseek
#endif
int64_t dtoend(FILE* fp)
{
int64_t curpos = bigtell(fp); // Saves the file's current position
if (bigseek(fp, 0LL, SEEK_END) != 0) return -1; // -1 can ONLY be an error condition
int64_t endpos = bigtell(fp); // Retrieve file size (end position)
bigseek(fp, curpos, SEEK_SET); // Restore previously saved position
return endpos - curpos; // Subtract to get distance from end
}
† 来自上面链接的同一 cplusplus.com 页面:
For streams open in text mode, offset shall either be zero or a value
returned by a previous call to ftell, and origin shall necessarily be
SEEK_SET. If the function is called with other values for these
arguments, support depends on the particular system and library
implementation (non-portable).
对于给定的文件指针(FILE *
),是否可以快速确定从当前位置到文件末尾的距离。
计算实际距离所需的时间应该与距离无关。
比如fpos_t
的减法,但是fpos_t不是整数,不能进行数值运算。还有其他方法吗?
For example the subtraction of fpos_t, but fpos_t is not integer, it cannot be operated numerically. Is there any alternative way?
不,你不能。
FILE 结构不知道文件有多长,因此没有简单的方法来找到这个距离。该文件被视为一条道路 - 您转入道路并沿着道路行驶,当道路结束时,您会发现。但是没有标志告诉你路有多长。
您可以单独询问 OS,使用 stat
或类似的。但请注意,FILE 甚至并不总是引用具有已定义结尾的文件 - 它可能 stdin
来自管道,并且当时大小完全未知。
当你第一次打开文件时,你可以使用fseek()
转到文件末尾(但请参阅下面的注释),然后使用ftell()
获取位置并保存(作为文件的大小)。然后调用rewind()
回到开头。
然后,可以从保存的 'size' 中减去以后调用 ftell()
的 return 值,以获得从当前位置到文件末尾的偏移量(距离) :
// Given a FILE* fp that's just been opened:
fseek(fp, 0, SEEK_END);
long int endpos = ftell(fp);
rewind(fp); // Or you can use fseek(fp, 0, SEEK_SET);
//...
// Later in your code:
long int dtoend = endpos - ftell(pf);
但请注意,实现 不需要 来实现 SEEK_END
:来自上面链接的 fseek
上的 cplusplus.com 页面:
- Library implementations are allowed to not meaningfully support SEEK_END (therefore, code using it has no real standard portability).
澄清一下(根据一些评论):上面的代码 要求 endpos
值在文件 open/read 操作。一个 可以 通过寻找结束然后在任何时候恢复 当前 位置来避免这种情况,但效率会低得多。例如,可以编写一个函数来随时获取到终点的距离:
long int dtoend(FILE *fp)
{
long int curpos = ftell(fp); // Get current position
fseek(fp, 0, SEEK_END); // Go to the file's end
long endpos = ftell(fp); // Gets the file's size
fseek(fp, curpos, SEEK_SET); // Restore previous pos
return endpos - curpos; // Return the distance!
}
使用大型(> 2GB)文件的注意事项:以上代码使用标准
fseek
和 ftell
函数,它们使用 long int
类型(即通常为 32 位宽)用于文件位置;要对较大的文件使用类似的代码,有许多(尽管是特定于平台的)替代方案...
在 Windows 平台上,使用 MSVC
(或兼容)编译器,有 _ftelli64
and _fseeki64
函数,它们的使用方式几乎与它们的 'standard'同行;例如,通过对上述代码进行以下更改:
//...
int64_t curpos = _ftelli64(fp); // Get current position
_fseeki64(fp, 0LL, SEEK_END); // Go to the file's end
//... and similar changes elsewhere
在 Linux 系统上,如果您 确保 ,则 64 位调用将实现为 ftello
and fseeko
至 #define _FILE_OFFSET_BITS 64
.
其他 platforms/compilers 可能会实现上述任一(或两者),或者有一些其他非常相似的 64 位替代品。
注释 #2 - 错误处理: 正如评论中所指出的,使用
SEEK_END
作为 origin 参数调用 fseek
可能会在多种不同情况下失败;例如,如果文件指针是 stdin
,如果它指的是管道流,或者(在某些系统上)如果文件以 文本模式 [=78= 打开]†。要处理这种情况,应该真正检查 fseek
调用的 return 值,如果失败,它将是 非零 。因此,这里是实现了此类错误处理的 dtoend
函数的 64 位版本(请注意 MSVC
或 GNU
以外的编译器,您需要添加相关的定义宏bigseek
和 bigtell
函数):
#include <stdio.h>
#include <stdint.h>
#if defined (_MSC_VER) // MSVC/Windows...
#define bigtell _ftelli64
#define bigseek _fseeki64
#elif defined (__GNUC__) // GNU/Linux...
#define _FILE_OFFSET_BITS 64
#define bigtell ftello
#define bigseek fseeko
//
// Feel free to add other compiler/platform implementations
//
#else // Unknown platform/compiler - likely to cause warnings!
#define bigtell ftell
#define bigseek fseek
#endif
int64_t dtoend(FILE* fp)
{
int64_t curpos = bigtell(fp); // Saves the file's current position
if (bigseek(fp, 0LL, SEEK_END) != 0) return -1; // -1 can ONLY be an error condition
int64_t endpos = bigtell(fp); // Retrieve file size (end position)
bigseek(fp, curpos, SEEK_SET); // Restore previously saved position
return endpos - curpos; // Subtract to get distance from end
}
† 来自上面链接的同一 cplusplus.com 页面:
For streams open in text mode, offset shall either be zero or a value returned by a previous call to ftell, and origin shall necessarily be SEEK_SET. If the function is called with other values for these arguments, support depends on the particular system and library implementation (non-portable).