是否建议使用fseek()计算文件大小的方法?

在C中,我们可以使用fseek()函数找到文件的大小。 喜欢,

 if (fseek(fp, 0L, SEEK_END) != 0) { // Handle repositioning error } 

所以,我有一个问题,是否建议使用fseek()ftell()计算文件大小的方法?

如果您使用的是Linux或其他类似UNIX的系统,那么您需要的是stat函数:

 struct stat statbuf; int rval; rval = stat(path_to_file, &statbuf); if (rval == -1) { perror("stat failed"); } else { printf("file size = %lld\n", (long long)statbuf.st_size; } 

在MSVC下的Windows上,您可以使用_stati64

 struct _stati64 statbuf; int rval; rval = _stati64(path_to_file, &statbuf); if (rval == -1) { perror("_stati64 failed"); } else { printf("file size = %lld\n", (long long)statbuf.st_size; } 

与使用fseek不同,此方法不涉及打开文件或搜索文件。 它只读取文件元数据。

fseek()/ftell() 有时会起作用。

 if (fseek(fp, 0L, SEEK_END) != 0) printf("Size: %ld\n", ftell(fp)); } 

问题。

  1. 如果文件大小超过大约LONG_MAX ,则long int ftell(FILE *stream)响应会出现问题。

  2. 如果文件在文本模式下打开,则ftell()的返回值可能与文件长度不对应。 “对于文本流,其文件位置指示符包含未指定的信息,”C11dr§7.21.9.42

  3. 如果文件以二进制模式打开,则fseek(fp, 0L, SEEK_END)定义不明确。 “将文件位置指示器设置为文件结尾,与fseek(file, 0, SEEK_END) ,具有二进制流的未定义行为(因为可能是尾随空字符)或具有状态相关编码的任何流不能确定在最初的轮class状态结束。“ C11dr脚注268. @Evert这通常适用于早于今天的平台,但它仍然是规范的一部分。

  4. 如果文件是串行输入或stdin输入的流,则fseek(file, 0, SEEK_END)没有多大意义。

查找文件大小的常用解决方案是非便携式平台特定的解决方案。 示例好的答案@dbush 。

注意:如果代码尝试根据文件大小分配内存,则文件大小很容易超出可用内存。

由于这些问题,我不推荐这种方法。

通常,应该重新解决问题, 不需要查找文件大小,而是在处理更多输入时增加数据。


LL免责声明:请注意,C规范脚注是提供信息的 ,因此不一定是规范性的

我认为最好的方法是fstat() : https : fstat()

那么,您可以通过以下几种方式估计文件的大小:

  • 您可以从头到尾read(2)文件,读取的数字或字符是文件的大小。 这是获取文件大小的繁琐方法,因为您必须读取整个文件才能获得大小。 但是如果操作系统不允许任意定位文件指针,那么这是获取文件大小的唯一方法。
  • 或者您可以将指针移动到文件位置的末尾。 这是你在问题中显示的lseek(2) ,但要注意你必须进行两次系统调用 ,因为返回的值是将指针移动到所需位置之前的实际位置。
  • 或者您可以使用stat(2)系统调用,它将告诉您文件的所有管理信息,例如文件在磁盘中占有的所有者,组,权限, 大小 ,块数,此文件所属的磁盘,指向它的目录条目数等。这允许您只使用一个系统调用获取所有这些信息。

你指出的其他方法(比如使用ftell(3) stdio库调用)也会起作用(同样的问题导致两个系统调用来设置和检索/恢复文件指针)但是存在涉及库的问题这可能是你没有用于其他任何东西。 在int文件描述符上获取FILE *指针(例如fdopen(3) )应该很复杂,只是为了能够对它使用ftell(3)函数(两次),然后再次fclose(3)它。