从文本文件读取,直到EOF重复上一行

以下C ++代码使用ifstream对象从文本文件(每行有一个数字)读取整数,直到它遇到EOF 。 为什么它读取最后一行的整数两次? 如何解决这个问题?

码:

#include <iostream> #include <fstream> using namespace std; int main() { ifstream iFile("input.txt"); // input.txt has integers, one per line while (!iFile.eof()) { int x; iFile >> x; cerr << x << endl; } return 0; } 

input.txt

 10 20 30 

输出

 10 20 30 30 

注意 :我跳过了所有错误检查代码,以保持代码片段小。 上述行为可以在Windows(Visual C ++),cygwin(gcc)和Linux(gcc)上看到。

只要密切关注事件链。

  • 抓住10
  • 抢20
  • 抓住30
  • 抓住EOF

看看倒数第二个迭代。 你抓了30,然后进行检查EOF。 您尚未到达EOF,因为EOF标记尚未读取(“二进制”说,其概念位置在30行之后)。 因此,你继续下一个迭代。 从以前的迭代x仍然是30。 现在你从stream中读取,你会得到EOF。 x保持30,ios :: eofbit被提升。 你输出到stderr x(这是30,就像在以前的迭代)。 接下来在循环条件中检查EOF,这次你不在循环中。

尝试这个:

 while (true) { int x; iFile >> x; if( iFile.eof() ) break; cerr << x << endl; } 

顺便说一下,你的代码中有另一个错误。 你有没有尝试在空文件上运行它? 你得到的行为是出于完全相同的原因。

我喜欢这个例子,现在,在while块中省略你可以添加的检查:

 ifstream iFile("input.txt"); // input.txt has integers, one per line int x; while (iFile >> x) { cerr << x << endl; } 

不知道它有多安全

有一个替代方法:

 #include <iterator> #include <algorithm> // ... copy(istream_iterator<int>(iFile), istream_iterator<int>(), ostream_iterator<int>(cerr, "\n")); 

EOF模式需要一个主要读取来“引导”EOF检查过程。 考虑到空文件在第一次读取之前最初不会有EOF设置。 在这种情况下,首读将捕获EOF,并完全跳过循环。

这里需要记住的是,在第一次尝试读取文件的可用数据之前,您不会得到EOF。 读取确切的数据量不会标记EOF。

我应该指出,如果这个文件是空的,你的代码将会打印出来,因为在进入循环时,EOF将阻止一个值被设置为x。

  • 0

因此,添加一个素数读取,并将循环的读取结束:

 int x; iFile >> x; // prime read here while (!iFile.eof()) { cerr << x << endl; iFile >> x; } 

没有对原始代码进行太多的修改,就可能变成:

 while (!iFile.eof()) { int x; iFile >> x; if (!iFile.eof()) break; cerr << x << endl; } 

但我更喜欢上面的其他两个解决scheme。

在最后一行的末尾,你有一个新的行字符,这是不是由>>操作符读取,它不是文件的结尾。 请做一个实验,并删除新行(文件中的最后一个字符) – 你不会得到重复。 要有一个灵活的代码,并避免不必要的影响,只适用于其他用户提供的任何解决scheme。

 int x; ifile >> x while (!iFile.eof()) { cerr << x << endl; iFile >> x; }