getline 设置 failbit 和 eof

nik*_*ohn 5 c++ exception getline eof

我知道这种行为的起源,因为它在 SO 的多篇文章中得到了很好的解释,一些值得注意的例子是:

为什么循环条件中的 iostream::eof 被认为是错误的?

使用 getline() 而不设置 failbit

std::getline 在遇到 eof 时抛出

C++ istream EOF 不保证failbit?

它也包含在std::getline标准中

3) 如果由于某种原因没有提取任何字符(甚至没有被丢弃的分隔符),getline 设置 failbit 并返回。

我的问题是如何处理这种行为,您希望您的流在failbit所有情况下捕获异常,但由于到达eof最后一行为空的文件的,引起的异常除外。有什么明显的我遗漏了吗?

MWE:

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


void f(const std::string & file_name, char comment) {

std::ifstream file(file_name);
file.exceptions(file.failbit);
    try {
          std::string line;

          while (std::getline(file, line).good()) {
          // empty getline sets failbit throwing an exception
            if ((line[0] != comment) && (line.size() != 0)) {
                std::stringstream ss(line);
                // do stuff
            }
        }
    }

    catch (const std::ios_base::failure& e) {
        std::cerr << "Caught an ios_base::failure.\n"
        << "Explanatory string: " << e.what() << '\n'
        << "Error code: " << e.code() << '\n';

        }
}


int main() {

    f("example.txt", '#');
}
Run Code Online (Sandbox Code Playgroud)

其中example.txt是一个制表符分隔的文件,它的最后一行只是\n字符:

# This is a text file meant for testing
0   9
1   8
2   7
Run Code Online (Sandbox Code Playgroud)

编辑:

while(std::getline(file, line).good()){...} 复制问题。

Dav*_*ica 3

避免设置的另一种方法failbit是简单地重构测试以检测空行if的读取。由于这是本例中的最后一行,因此您可以简单地避免抛出错误,例如:return

    std::ifstream file (file_name);
    file.exceptions (file.failbit);
    try {
        std::string line;

        while (std::getline(file, line)) {
            // detect empty line and return
            if (line.size() == 0)
                return;
            if (line[0] != comment) {
                std::stringstream ss(line);
                // do stuff
            }
        }
    }
    ...
Run Code Online (Sandbox Code Playgroud)

您的另一种选择是检查是否eofbit在 中设置catch。如果eofbit设置了——读取成功完成。例如

    catch (const std::ios_base::failure& e) {
        if (!file.eof())
            std::cerr << "Caught an ios_base::failure.\n"
            << "Explanatory string: " << e.what() << '\n'
            << "Error code: " /* << e.code() */ << '\n';
    }
Run Code Online (Sandbox Code Playgroud)

  • @nikjohn - 另一个简单的修复方法是将 `if (!file.eof())` 包含为 `catch` 中的第一行。 (2认同)