【问题标题】:Why does C++ fstream require call to clear() after calling std::getline in a loop为什么在循环中调用 std::getline 后 C++ fstream 需要调用 clear()
【发布时间】:2020-11-18 05:04:05
【问题描述】:

在以下代码中,我使用 std::getline 从仅包含“12345”的文件中读取,并在尝试将“67890”写入文件后立即读取。除非我首先调用 myfile.clear(),否则此写入将失败。为什么是这样?究竟是什么破?有没有办法在循环中仍然使用 std::getline 但防止在读取最后一行时发生错误?什么是正确的?

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

using std::cout;
using std::fstream;
using std::string;

void printStats(fstream&);

int main(int argc, char* argv[])
{
    // textfile.txt:
    // 1234 
    fstream myfile("textfile.txt", std::fstream::in | std::fstream::out);
    string line;
    
    cout << "\n"
         << "Before reading lines in a loop.\n";
    printStats(myfile);
    
    cout << "\n" 
         << "Reading lines in the loop.\n";
    while (myfile.eof() != true)
    {   
        std::getline(myfile, line);     // Last call here causes EOF and FAIL bit to be set
        cout << "line=" << line << "\n";
    }
    
    cout << "\n" 
         << "After reading lines in a loop.\n";
    printStats(myfile);
    
    myfile.clear(); // If I comment this out the write below fails
    
    myfile << "67890\n";
    
    myfile.close();
    
    return 0;
}

void printStats(fstream& fileStream)
{
    int position = fileStream.tellp();
        cout << "position = " << position << "\n";

    if (fileStream.eof() == true)
        cout << "EOF bit  = 1\n";
    else
        cout << "EOF bit  = 0\n";

    if (fileStream.fail() == true)
        cout << "FAIL bit = 1\n";
    else
        cout << "FAIL bit = 0\n";

    if (fileStream.bad() == true)
        cout << "BAD bit  = 1\n";
    else
        cout << "BAD bit  = 0\n";
}

以下是 myfile.clear() 被注释掉的执行结果:

user@Ubuntu:~/example/test$ cat textfile.txt ; ./test ; cat textfile.txt 
12345

Before reading lines in a loop.
position = 0
EOF bit  = 0
FAIL bit = 0
BAD bit  = 0

Reading lines in the loop.
line=12345
line=

After reading lines in a loop.
position = -1
EOF bit  = 1
FAIL bit = 1
BAD bit  = 0
12345

以下是使用代码中包含的 myfile.clear() 执行的结果:

user@Ubuntu:~/example/test$ cat textfile.txt ; ./test ; cat textfile.txt 
12345

Before reading lines in a loop.
position = 0
EOF bit  = 0
FAIL bit = 0
BAD bit  = 0

Reading lines in the loop.
line=12345
line=

After reading lines in a loop.
position = -1
EOF bit  = 1
FAIL bit = 1
BAD bit  = 0
12345
67890

这是在 Ubuntu Linux 20.04 上使用 g++ 编译的

user@Ubuntu:~/example/test$ /usr/bin/g++ --version
g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

我确实在下面找到了类似的结果,但它没有清楚地解释我的问题的答案。

c++ getline() looping when used in file with a read in int array?

【问题讨论】:

  • 好,完整的问题,但是您可以通过查看 clear 的文档来了解它的作用,从而节省一些时间。
  • 这并没有解决问题,但while (myfile.eof() != true) 通常写成while (!myfile.eof())。但是,如果您真的非常想与显式值进行比较,那么写 while (myfile.eof() == false) 会更清楚。

标签: c++


【解决方案1】:

您似乎遇到了why while(!in.eof()) is usually wrong 的问题。 eofbit 直到您尝试读取文件末尾之后才设置,因为您使用getline 这样做会导致failbit 也被设置。然后当myfile.fail() 为真时流拒绝写入,直到你清除它为止。

【讨论】:

  • 是的,但是有什么方法可以使用 getline 来读取文件末尾的内容吗?
  • 我认为你是对的,事实上。更改为while(getline(myfile, line)) 仍将保留故障位设置并需要调用myfile.clear(),它只会产生在到达EOF 后没有cout 空行的效果。但它更清楚地表明,您不能指望在执行读取之前尝试警惕检查 EOF 来永远设置故障位。
  • 是的,当我执行看似完全正常的操作时,我需要清除错误设置,这似乎很奇怪。与在 C 中处理文件相比,我一直发现 C++ 流既麻烦又不直观。无论如何,我想这回答了我的问题。任何时候你读到文件末尾都必须清除失败位。
猜你喜欢
  • 1970-01-01
  • 2015-07-16
  • 2013-11-02
  • 2013-09-10
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
  • 2010-10-08
  • 1970-01-01
相关资源
最近更新 更多