从文本文件读取,直到 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)上可以看到上述行为。

350262 次浏览

只要密切关注事态的发展就行了。

  • 拿十个
  • 抓住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;
}

顺便说一下,您的代码中还有另一个 bug。你试过用空文件运行吗?你的行为也是出于同样的原因。

我喜欢这个例子,它省略了您可以在 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"));

如果不对原始法典进行大量修改,它可能会变成:

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

但总的来说,我更喜欢上面提到的另外两种解决方案。

int x;
ifile >> x


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

EOF 模式需要一个基本读数来“引导”EOF 检查过程。考虑到在第一次读取之前,空文件最初不会有它的 EOF 集。主读将在此实例中捕获 EOF 并正确地完全跳过循环。

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

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

  • 0

因此,添加一个主读,并将循环的读移动到末尾:

int x;


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

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