ifstream的eof()如何工作?

时间:2010-12-26 07:21:53

标签: c++ ifstream eof

#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 个答案:

答案 0 :(得分:67)

-1是get说你到达文件末尾的方式。使用std::char_traits<char>::eof()(或std::istream::traits_type::eof())比较它 - 避免-1,这是一个神奇的数字。 (虽然另一个有点冗长 - 你可以随时拨打istream::eof

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

第二个示例有效,因为inf >> foo将始终返回inf,其副作用是尝试读取内容并将其存储在foo中。如果文件“良好”,infif中的while将评估为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.
}

这就是我们想要的。

答案 1 :(得分:7)

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

sample code at 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;

答案 2 :(得分:6)

EOF标志仅在读取操作尝试读取超过文件末尾后设置。 get()返回符号常量traits::eof()(恰好等于-1),因为它到达文件的末尾并且无法读取更多数据,并且仅在此时eof() int ch; while ((ch = inf.get()) != EOF) { std::cout << static_cast<char>(ch) << "\n"; } } 是真的。如果要检查此情况,可以执行以下操作:

{{1}}

答案 3 :(得分:2)

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

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

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