Aud*_*cot 1 c position file eof file-pointer
对于给定的文件指针(FILE *),是否可以快速确定从当前位置到文件末尾的距离。
计算实际距离所需的时间不应取决于距离。
比如减法fpos_t,但是fpos_t不是整数,不能进行数值运算。有什么替代方法吗?
当您第一次打开文件时,您可以使用fseek()转到文件末尾(但请参阅下面的注释),然后使用ftell()获取位置并将其保存(作为文件的大小)。然后调用rewind()返回到开始。
然后,ftell()可以从您保存的“大小”中减去任何后续调用的返回值,以获得从当前位置到文件末尾的偏移量(距离):
// 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);
Run Code Online (Sandbox Code Playgroud)
但请注意,不需要实现SEEK_END:来自fseek上面链接的 cplusplus.com 页面:
- 允许库实现无意义地支持 SEEK_END(因此,使用它的代码没有真正的标准可移植性)。
只是为了澄清(遵循一些评论):上面的代码要求endpos在文件的打开/读取操作期间保存该值。一个可以寻求到年底,然后恢复到避免这种当前位置在任何时候,但是这将是效率很低的。例如,可以编写一个函数来随时获取到终点的距离:
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!
}
Run Code Online (Sandbox Code Playgroud)
fseek和ftell函数,这些标准和函数使用long int类型(通常为 32 位宽)作为文件位置;要对较大的文件使用类似的代码,有许多(尽管是特定于平台的)替代方案......
在 Windows 平台上,使用MSVC(或兼容的)编译器,有_ftelli64和_fseeki64函数,它们的使用方式几乎与“标准”对应物相同;例如,通过对上述代码进行以下更改:
//...
int64_t curpos = _ftelli64(fp); // Get current position
_fseeki64(fp, 0LL, SEEK_END); // Go to the file's end
//... and similar changes elsewhere
Run Code Online (Sandbox Code Playgroud)
在Linux系统中,64位调用被实现为ftello和fseeko,如果你确保到#define _FILE_OFFSET_BITS 64。
其他平台/编译器可能会实现上述任一(或两者),或者具有其他一些非常相似的 64 位替换。
fseek与SEEK_END作为原点参数可以根据不同情节数失败; 例如,如果文件指针是stdin,如果它指的是管道流,或者(在某些系统上)如果文件以文本模式打开†。为了处理这种情况,我们应该真正检查fseek调用的返回值,如果调用失败,返回值将是非零的。因此,这是一个 64 位版本的dtoend函数,其中实现了此类错误处理(注意除了MSVCor之外的编译器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
}
Run Code Online (Sandbox Code Playgroud)
†来自上面链接的同一个cplusplus.com页面:
对于以文本模式打开的流,偏移量应为零或先前调用 ftell 返回的值,并且来源必须为 SEEK_SET。如果使用这些参数的其他值调用该函数,则支持取决于特定的系统和库实现(不可移植)。