C ++中的文件处理

问题描述 投票:0回答:3

我编写了以下代码来从文件中输入数字,但是最后一个数字被打印了两次,我感到很困惑。可能的答案是什么。预先感谢。

代码:

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    int x;
    ifstream f;
    f.open("note");
    while(!f.eof()){
            f>>x;
            cout<<x<<endl;
    }
    return 0;
}

给出输出:

1
2
3
4
5
5

文件注释的内容是:

1
2
3
4
5 
c++ file-handling
3个回答
3
投票

到目前为止提供的每个解决方案都很好地解释了为什么OP代码错误。但是大多数人对该问题的解决方法不正确。

如您尝试读取文件末尾之前,多次未设置EOF标志之前所述。最后一次成功读取可能会读取(包括)最后一个字符。因此,根据您的情况,最后一次读取将从文件中读取5,然后将其打印出来。然后,我们进入租户循环(这将起作用,因为最后一次读取未读取到文件末尾,因此EOF为false)。您尝试读取下一个字符的尝试将在f >> x处失败,并且变量'x'将保持不变(在您的代码中,这意味着它的最后一个值读为5),然后将其打印出来。

解决方案是在完成读取后测试流的条件以确保其正常工作。注意:您不应该专门测试EOF是否存在其他不良状态。如果输入了其他不良状态之一,则当前代码将进入无限循环。要检查所有不良位,请在对象上调用fail()。因此,最简单的解决方案是将读取内容放入while测试中(请参见下文)

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    int x;
    ifstream f;
    f.open("note");
    while(f>>x)
    {
            cout<<x<<endl;
    }
    return 0;
}

这是有效的,因为>>运算符返回一个流。当在布尔上下文中使用流对象时,会将其转换为可以表示true / false的类型(出于技术原因,这不是bool,但您可以将其视为bool)。返回的值取决于流的状态。如果流处于良好状态,则它将(在布尔上下文中)评估为true,从而允许进入循环,如果流对象处于无效状态(即EOF(或其他失败状态)为true),则它将评估为false并且未进入循环。

注意:转换实际上在流上调用fail()来测试状态。

如果您的代码很复杂,并且您不能在读取时测试状态。然后,在每次读取之后,您必须测试对象的状态以验证其是否有效。

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
    int x;
    ifstream f;
    f.open("note");
    while(f)
    {
            f>>x;
            if (f) // dont' use f.eof() there are other bad states.
            {      // This will actuall call f.fail() which test for all bad states.
                   // Thus it only prints if the read worked.

                  cout<<x<<endl;
            }
            // Alternatively you can put the read into the if
            if ( f >> x)
            {
                  // STUFF
            }
    }
    return 0;
}

回应吉姆的评论。使用>>运算符从流中读取数字后。没有其他字符被读取。为了证明这是真的,请尝试以下代码:

#include <iostream>
#include <fstream>
#include <string>

int main()
{
    std::ifstream  file("txt");
    std::string    line;
    int            x;

    while(f >> x)
    {
        std::getline(f, line);   // If the '\n' was read then
                                 // this code would remove the next line.
                                 // As it works correctly it simply removes then
                                 // characters upto the newline character after the number.
        std::cout << x << "\n";
    }
}

6
投票

让我尝试比这里以前的答案更具启发性。 f>>x读取一个整数,以便扫描输入中的数字。它看到的是“ 5”,然后是“ \ n”,这不是一个数字,因此它将在“ 5”之后停止并将x设置为5。它尚未遇到eof,您的循环将再次执行,然后f>>x读取'\ n',然后在达到eof时失败,使x保持不变,然后再次打印5。因此,您需要在阅读后和打印之前进行测试。最简单(也是首选)的方法是

while(f>>x)
    cout<<x<<endl;

您应该not做类似的事情

do{
    f>>x;
    cout<<x<<endl;
}while(!f.eof());

((在读取后和打印之前不会进行测试),因为如果输入文件中不包含任何数字,则会导致未定义的行为-x进行了单位化,因此您将打印垃圾(或可能会破坏世界,但是可能不是)。


5
投票

这是因为仅当您尝试读取EOF之后才设置EOF标志。 (这是一个错误标志)

因此,最好在循环结束时测试f.eof()

© www.soinside.com 2019 - 2024. All rights reserved.