46
#include <iostream>
#include <fstream>

int main() {
    std::fstream inf( "ex.txt", std::ios::in );
    while( !inf.eof() ) {
        std::cout << inf.get() << "\n";
    }
    inf.close();
    inf.clear();
    inf.open( "ex.txt", std::ios::in );
    char c;
    while( inf >> c ) {
        std::cout << c << "\n";
    }
    return 0;
}

我真的对eof()功能感到困惑。假设我 ex.txt 的内容是:

abc

它总是读取一个额外的字符并-1在使用读取时显示eof()。但是inf >> c给出了正确的输出是'abc'?谁能帮我解释一下?

4

4 回答 4

78

-1get表示您已到达文件末尾。std::char_traits<char>::eof()使用(or )比较它std::istream::traits_type::eof()- 避免 -1,这是一个神奇的数字。(虽然另一个有点冗长 - 你总是可以打电话istream::eof

只有在读取尝试读取文件末尾之后才设置 EOF 标志。如果我有一个 3 字节的文件,而我只读取了 3 个字节,则 EOF 是false,因为我还没有尝试读取文件末尾。虽然这对于通常知道其大小的文件来说似乎令人困惑,但直到在某些设备(例如管道和网络套接字)上尝试读取时才知道 EOF。

第二个示例inf >> foo将始终返回inf,并尝试读取某些内容并将其存储在foo. inf, 在iforwhile中,将评估true文件是否“好”:没有错误,没有 EOF。因此,当读取失败时,inf评估为false,并且您的循环正确中止。但是,请采取以下常见错误:

while(!inf.eof())  // EOF is false here
{
    inf >> x;      // read fails, EOF becomes true, x is not set
    // use x       // we use x, despite our read failing.
}

然而,这:

while(inf >> x)  // Attempt read into x, return false if it fails
{
    // will only be entered if read succeeded.
}

这就是我们想要的。

于 2010-12-26T07:38:44.937 回答
8

只有在读取操作尝试读取文件末尾之后才会设置 EOF 标志。get()正在返回符号常量traits::eof()(恰好等于 -1),因为它到达了文件的末尾并且无法读取更多数据,并且只有在这一点上才会eof()为真。如果要检查这种情况,可以执行以下操作:

int ch;
while ((ch = inf.get()) != EOF) {
    std::cout << static_cast<char>(ch) << "\n";
}
于 2010-12-26T07:29:50.053 回答
7

iostream 不知道它在文件末尾,直到它尝试读取文件末尾之后的第一个字符。

cplusplus.com 上的示例代码说要这样做:(但你实际上不应该这样做)

  while (is.good())     // loop while extraction from file is possible
  {
    c = is.get();       // get character from file
    if (is.good())
      cout << c;
  }

一个更好的习惯用法是将读取移动到循环条件中,如下所示:(您可以对所有 istream返回的读取操作执行此操作*this,包括>>运算符)

  char c;
  while(is.get(c))
    cout << c;
于 2010-12-26T07:31:50.277 回答
2

eof() 检查流状态中的 eofbit。

在每次读取操作时,如果位置位于流的末尾并且必须读取更多数据,则将 eofbit 设置为 true。因此,在获得 eofbit=1 之前,您将获得一个额外的字符。

正确的方法是在读取操作后检查是否到达eof(或者,读取操作是否成功)。这是您的第二个版本所做的 - 您执行读取操作,然后使用生成的流对象引用(>> 返回)作为布尔值,这将导致检查失败()。

于 2010-12-26T07:35:38.973 回答