2008-08-22 70 views
104

以下C++代码使用ifstream的对象读取从文本文件中的整数(其具有每行一个数),直到它碰到EOF。为什么它读取最后一行的整数两次?如何解决这个问题?从文本文件中读取直到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)上看到。

回答

109

只需密切关注事件链。

  • 抓斗10
  • 抓斗20
  • 抓斗30
  • 抓斗EOF

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

试试这个:

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

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

+40

使用'while(iFile >> x)'。这读取整数并返回流。当流被用作bool值时,它会检查流是否有效。有效意味着eof()和bad()都是错误的。请参阅http://stackoverflow.com/questions/21647/c-reading-from-text-file-until-eof-repeats-last-line#21666 – 2008-09-23 07:48:02

+3

与注释相同的精神:而不是`while(true)`,看起来最好写'while(file.good())` – PHF 2012-04-13 15:14:42

29

我喜欢这个例子中,这对于现在离开了,你可以添加,而块内的检查:

ifstream iFile("input.txt");  // input.txt has integers, one per line 
int x; 

while (iFile >> x) 
{ 
    cerr << x << endl; 
} 

不知道它是如何安全...

16

有一种替代方法为此:

#include <iterator> 
#include <algorithm> 

// ... 

    copy(istream_iterator<int>(iFile), istream_iterator<int>(), 
     ostream_iterator<int>(cerr, "\n")); 
5

没有原码的多的修改,它可能成为:

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

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

2
int x; 
ifile >> x 

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

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

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

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

所以加一个素读取和移动环路的读到结尾:

int x; 

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

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