C++ 从文本文件中读取直到 EOF 重复最后一行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21647/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:17:15  来源:igfitidea点击:

Reading from text file until EOF repeats last line

c++iostreamfstream

提问by Ashwin Nanjappa

The following C++code uses a ifstreamobject to read integers from a text file (which has one number per line) until it hits EOF. Why does it read the integer on the last line twice? How to fix this?

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

Code:

代码:

#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:

输入.txt

10  
20  
30

Output:

输出

10  
20  
30  
30

Note: I've skipped all error checking code to keep the code snippet small. The above behaviour is seen on Windows (Visual C++), cygwin (gcc) and Linux (gcc).

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

回答by wilhelmtell

Just follow closely the chain of events.

只需密切关注事件链。

  • Grab 10
  • Grab 20
  • Grab 30
  • Grab EOF
  • 抢 10
  • 抢 20
  • 抢30
  • 抓取EOF

Look at the second-to-last iteration. You grabbed 30, then carried on to check for EOF. You haven't reached EOF because the EOF mark hasn't been read yet ("binarically" speaking, its conceptual location is just after the 30 line). Therefore you carry on to the next iteration. x is still 30 from previous iteration. Now you read from the stream and you get EOF. x remains 30 and the ios::eofbit is raised. You output to stderr x (which is 30, just like in the previous iteration). Next you check for EOF in the loop condition, and this time you're out of the loop.

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

Try this:

尝试这个:

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

By the way, there is another bug in your code. Did you ever try to run it on an empty file? The behaviour you get is for the exact same reason.

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

回答by Patrick Loz

I like this example, which for now, leaves out the check which you could add inside the while block:

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

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

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

Not sure how safe it is...

不确定它有多安全......

回答by wilhelmtell

There's an alternative approach to this:

对此有一种替代方法:

#include <iterator>
#include <algorithm>

// ...

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

回答by Solostaran14

Without to much modifications of the original code, it could become :

无需对原始代码进行太多修改,它可能会变成:

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

but I prefer the two other solutions above in general.

但总的来说,我更喜欢上面的其他两种解决方案。

回答by Brian Hyman

The EOF pattern needs a prime read to 'bootstrap' the EOF checking process. Consider the empty file will not initially have its EOF set until the first read. The prime read will catch the EOF in this instance and properly skip the loop completely.

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

What you need to remember here is that you don't get the EOF until the first attempt to read past the available data of the file. Reading the exact amount of data will not flag the EOF.

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

I should point out if the file was empty your given code would have printed since the EOF will have prevented a value from being set to x on entry into the loop.

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

  • 0
  • 0

So add a prime read and move the loop's read to the end:

所以添加一个主要读取并将循环的读取移动到最后:

int x;

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

回答by Raf

At the end of the last line, you have a new line character, which is not read by >> operator and it is not an end of file. Please, make an experiment and delete the new line (thelast character in file) - you will not get the duplication. To have a flexible code and avoid unwanted effects just apply any solution given by other users.

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

回答by user1384482

int x;
ifile >> x

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