有没有fseek / ftell可以提供错误文件大小的情况?

时间:2012-02-03 20:46:36

标签: c++ c porting fseek ftell

在C或C ++中,以下内容可用于返回文件大小:

const unsigned long long at_beg = (unsigned long long) ftell(filePtr);
fseek(filePtr, 0, SEEK_END);
const unsigned long long at_end = (unsigned long long) ftell(filePtr);
const unsigned long long length_in_bytes = at_end - at_beg;
fprintf(stdout, "file size: %llu\n", length_in_bytes);

是否存在基于填充或特定情况的其他信息从此代码返回错误文件大小的开发环境,编译器或操作系统?在1999年左右,C或C ++规范是否有变化,这会导致此代码在某些情况下不再起作用?

对于这个问题,请假设我通过使用标志-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1进行编译来添加大文件支持。感谢。

4 个答案:

答案 0 :(得分:6)

它不适用于/proc/cpuinfo/dev/stdin/dev/tty等不可搜索的文件,或popen获取的管道文件

如果该文件由另一个进程同时写入,则无效。

使用Posix stat功能可能更有效,更可靠。当然,非Posix系统可能无法使用此功能。

答案 1 :(得分:3)

fseekftell函数都是由ISO C语言标准定义的。

以下内容来自2011 C标准的latest public draft,但1990,1999和2011 ISO C标准在这方面非常相似,如果不相同的话。

7.21.9.4:

  

ftell 函数获取文件位置的当前值   指向的流的指示符。对于二进制流,   该值是文件开头的字符数。   对于文本流,其文件位置指示符包含未指定    fseek 函数可用于返回文件的信息   流的位置指示器到达时的位置    ftell 致电;两个这样的返回值之间的差异不是   必然是一个有意义的措施,写入的字符数   或阅读。

7.21.9.2:

  

fseek 函数设置流的文件位置指示符    stream 指出。如果发生读或写错误,则表示错误   设置了流的指示符, fseek 失败。

     

对于二进制流,新位置,以字符为单位   文件的开头是通过将偏移添加到   由 whence 指定的位置。指定的位置是   文件的开头如果从哪里 SEEK_SET ,则为当前值   文件位置指示符如果 SEEK_CUR ,或文件结束if   的 SEEK_END 即可。二进制流无需支持 fseek 调用 SEEK_END

     

对于文字流,偏移应为零,或偏移   应该是早先成功拨打电话所返回的值   与同一文件关联的流上的 ftell 功能从哪里 SEEK_SET

违反任何“shall”子句会导致程序的行为未定义。

因此,如果文件是以二进制模式打开的,ftell会为您提供文件开头的字符数 - 但相对于文件末尾的fseek({{1} }})不一定有意义。这适用于在整个块中存储二进制文件的系统,并且不会跟踪写入最终块的数量。

如果文件是在文本模式下打开的,您可以使用偏移量0来搜索文件的开头或结尾,或者您可以寻找之前调用SEEK_END给出的位置; ftell与任何其他参数具有未定义的行为。这适用于从文本文件中读取的字符数不一定与文件中的字节数相对应的系统。例如,在Windows上读取CR-LF对(fseek)只读取一个字符,但在文件中前进2个字节。

实际上,在类Unix系统上,文本和二进制模式的行为方式相同,而fseek / ftell方法也可以。我怀疑它可以在Windows上运行(我的猜测是"\r\n"会给出字节偏移量,这可能与您调用ftell的次数不一致文字模式)。

另请注意,getchar()会返回ftell()类型的结果。在long为32位的系统上,此方法不适用于2 GiB或更大的文件。

最好使用某种特定于系统的方法来获取文件的大小。因为fseek / ftell方法无论如何都是系统特定的,例如类Unix系统上的long

另一方面,stat()fseek可能会在您可能遇到的大多数系统上按预期工作。我确信有些系统无法运行;对不起,但我没有具体细节。

如果在Linux和Windows上运行足够好,你不关心大文件,那么fseek / ftell方法可能没问题。否则,您应该考虑使用特定于系统的方法来确定文件的大小。

请记住,任何告诉您文件大小的内容只能告诉您当时的大小。在您访问文件之前,文件的大小可能会发生变化。

答案 2 :(得分:2)

1)从表面上看,您的代码看起来“没问题” - 我没有看到任何问题。

2)否 - 没有任何“C或C ++规范”会影响fseek。 Posix规范:

3)如果你想要“文件大小”,我的第一选择可能是“stat()”。这是Posix规范:

4)如果你的方法“出错”,那么我的第一个猜测是“大文件支持”。

例如,许多操作系统都有并行的“fseek()”和“fseek64()”API。

'希望有所帮助.. PSM

答案 3 :(得分:1)

POSIX将fseek的返回值定义为“从文件开头以字节为单位”。您的at_beg将始终为零(假设这是一个新打开的文件)。

所以,假设:

  1. 该文件可以搜索
  2. 没有并发问题需要关注
  3. 文件大小可在您选择的fseek / ftell变体使用的数据类型中表示
  4. 那么您的代码应该适用于任何符合POSIX标准的系统。