C语言 是否推荐使用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 = %lldn", (long long)statbuf.st_size;
}

在Windows MSVC下,您可以使用_stati64:

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

与使用fseek不同,此方法不需要打开文件或查找文件。它只是读取文件元数据。

fseek()/ftell()工作有时

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

问题。

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

  2. 如果以文本方式打开文件,ftell()的返回值可能与文件长度不对应。"对于文本流,其文件位置指示器包含未指定的信息"C11dr§7.21.9.4 2

  3. 如果文件以二进制模式打开,则fseek(fp, 0L, SEEK_END)没有很好定义。将文件位置指示符设置为文件结束符,如fseek(file, 0, SEEK_END),对于二进制流(因为可能的尾空字符)或任何具有状态依赖编码的流(不确定以初始移位状态结束)具有未定义的行为。C11dr脚注268@Evert这通常适用于比现在更早的平台,但它仍然是规范的一部分。

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

查找文件大小的通常解决方案是一个非可移植平台特定的解决方案。答得好@布什。

注意:如果代码试图根据文件大小分配内存,那么可用的内存很容易被文件大小超过。

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

通常情况下,应该重新处理这个问题,使不需要来查找文件大小,而是随着处理更多输入而增加数据。


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

我认为最好的方法是fstat(): https://linux.die.net/man/2/fstat

嗯,你可以用几种方法来估计文件的大小:

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

您指向的其他方法(如使用ftell(3) stdio库调用)也可以工作(同样的问题是它会导致两个系统调用来设置和检索/恢复文件指针),但存在涉及可能不用于其他任何事情的库的问题。在int文件描述符上获得FILE *指针(例如fdopen(3))应该是复杂的,只是为了能够在其上使用ftell(3)函数(两次),然后再次使用fclose(3)

最新更新