【发布时间】:2012-02-05 16:44:13
【问题描述】:
免责声明:不要使用::feof() 作为循环条件。例如,请参阅答案:file reading: feof() for binary files
但是,我有“真实”代码演示了一个不使用 ::feof() 作为我的循环条件的问题,但从逻辑上讲,这是演示该问题的最简单方法。
考虑以下情况:我们一次迭代一个字符流:
FILE* my_file;
// ...open "my_file" for reading...
int c;
while(0 == ::feof(my_file))
{ // We are not at EOF
c = ::getc(my_file);
// ...process "c"
}
上面的代码按预期工作:文件一次处理一个字符,在EOF时,我们退出。
但是,以下有意外行为:
FILE* my_file;
// ...open "my_file" for reading...
int c;
while(0 == ::_eof(::fileno(my_file)))
{ // We are not at EOF
c = ::getc(my_file);
// ...process "c"
}
我原以为他们会执行相同的操作。 ::fileno() 每次都正确返回(整数)文件描述符。但是,测试::_eof(::fileno(my_file))只运行一次,然后在第二次尝试时返回1(表示EOF)。
我不明白。
我想::feof() 是“缓冲的”(因此它可以正常工作)是可以想象的,而::_eof() 是“未缓冲的”并且认为整个文件已经是“读入”的(因为整个文件会已适合从磁盘读取的第一个块)。但是,考虑到这些功能的目的,这不可能是真的。所以,我真的很茫然。
发生了什么事?
(文件以“文本”形式打开,是大约十几行的 ASCII 文本文件,MSVS2008,Win7/64。)
【问题讨论】:
-
你应该检查 getc() 的返回值来检查 EOF。 if(c!=EOF) cplusplus.com/reference/clibrary/cstdio/getc
-
您的代码仍然不正确。您必须检查 EOF after 读取但 before 处理。在遇到文件结尾之前,您不会看到它。
-
同意上述两个 cmets (@Rajendran && @Kerrek)。但是,这些问题在我的用例中不存在:文件不是空的,并且有多行;
feof()工作正常;_eof(fileno())在读取第一个字符后失败(返回1)。因此,那些关于我的“不正确条件”的合法投诉不适用于本案。 (这就是我以免责声明开头的原因。) -
事实上它确实适用于您的情况。 Rajendran 和 Kerrek 所说的是与您链接的问题不同的问题,并且不仅适用于空文件。 feof 在您读取文件的最后一个字节后不返回 1,在您尝试读取文件末尾的 PAST 后它返回 1。因此,您将 EOF 作为循环中的字符处理。
-
@Gerald,我没有看到/理解它:在一个包含多行的文件上恰好有一个
getc()之后,_eof()返回1。它在第一次读取之前返回0,并且第一次读取(正确)返回一个字符(并且不在EOF)。我仍在尝试理解您在下面的答案,以及_eof()的目的是什么,如果它总是返回1,即使您没有阅读任何内容(在第一个字符之后)。
标签: c++ file-io stream filestream