为什么:: feof()与:: _ eof(:: fileno())不同?

时间:2012-01-09 03:05:16

标签: c++ file-io stream filestream

免责声明:请勿使用::feof()作为循环条件。例如,请参阅以下答案:file reading: feof() for binary files

但是,我的“真实”代码演示了一个问题,即不使用::feof()作为我的循环条件,但是LOGICALLY,这是演示问题的最简单方法。

请考虑以下事项:我们一次迭代一个字符流:

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()是“未缓冲的”并认为整个文件已经“读入”了(因为整个文件将适合从磁盘读入的第一个块)。但是,考虑到这些功能的目的,这可能不是真的。所以,我真的很茫然。

发生了什么事?

(文件以“文本”打开,是包含大约十几行的MSF文件文件,MSVS2008,Win7 / 64.)

1 个答案:

答案 0 :(得分:5)

  

我认为可以想象:: feof()是“缓冲的”(因此它可以工作   正确)while :: _ eof()是“un-buffered”并认为整个文件   已经“读入”了(因为整个文件都适合   第一个块从磁盘读入)。但是,这可能不是真的   鉴于这些功能的目的。所以,我真的很茫然。

我不知道为什么你会认为“鉴于这些功能的目的,它不可能是真的。”这2个函数用于对以不同方式打开和操作的文件进行操作,因此它们不兼容。

事实上,这正是发生的事情。试试这个:

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);

  long offset1 = ftell(my_file);
  long offset2 = _tell(fileno(my_file));

  if (offset1 != offset2)
  {
     //here you will see that the file pointers are different
     //which means that _eof and feof will fire true under different conditions
  }
  // ...process "c"
}

我会根据你的评论来详细说明一下。

当您调用fopen时,您将返回指向文件 stream 的指针。底层流对象保留了它自己的文件指针,该指针与与底层文件描述符关联的实际文件指针分开。

当您调用_eof时,您会询问是否已到达实际文件的末尾。当您调用feof时,您会询问是否已到达文件 stream 的末尾。由于文件流通常是缓冲的,因此在流结束之前会到达文件的末尾。

  

我仍然试图理解你的答案,以及目的是什么   是_eof(),如果它总是返回1,即使你没有阅读   任何事情(在第一个字符之后)。

要回答这个问题,_eof的目的是确定在使用_open和_read直接使用文件描述符时是否已到达文件的末尾,而不是在使用fopen和fread或getc处理文件流时