getline设置failbit以及eof

时间:2018-06-03 02:45:49

标签: c++ exception getline eof

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

Why is iostream::eof inside a loop condition considered wrong?

Use getline() without setting failbit

std::getline throwing when it hits eof

C++ istream EOF does not guarantee failbit?

它也包含在std::getline standard

  

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", '#');
}

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

# This is a text file meant for testing
0   9
1   8
2   7

修改

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

2 个答案:

答案 0 :(得分:2)

避免设置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
            }
        }
    }
    ...

另一种方法是检查eofbit中是否设置了catch。如果设置了eofbit,则读取成功完成。 E.g。

    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';
    }

答案 1 :(得分:1)

编辑:我误解了OP,请参阅David的上述答案。此答案用于检查文件是否具有终止换行符。

while (getline)循环结束时,请检查file.eof()

假设你刚刚为文件的最后一行做了std::getline()

  • 如果后面有\n,则std::getline()已读取分隔符,但未设置eofbit。 (在这种情况下,下一个std::getline()将设置eofbit。)

  • 如果之后没有\n,那么std::getline()已阅读EOF并设置了eofbit

在这两种情况下,下一个std::getline()将触发failbit并输入您的异常处理程序。

PS:如果if ((line[0] != comment) && (line.size() != 0)) {为空,则行line为UB。条件的顺序需要颠倒。

相关问题