简体   繁体   English

getline设置failbit以及eof

[英]getline setting failbit along with eof

I am aware of the origin of this behavior since it has been very well explained in multiple posts here in SO, some notable examples are: 我知道这种行为的起源,因为它在SO中的多个帖子中得到了很好的解释,一些值得注意的例子是:

Why is iostream::eof inside a loop condition considered wrong? 为什么循环条件中的iostream :: eof被认为是错误的?

Use getline() without setting failbit 使用getline()而不设置failbit

std::getline throwing when it hits eof 当它击中eof时std :: getline投掷

C++ istream EOF does not guarantee failbit? C ++ istream EOF不保证failbit?

And it is also included in the std::getline standard : 它也包含在std::getline标准中

3) If no characters were extracted for whatever reason (not even the discarded delimiter), getline sets failbit and returns. 3)如果由于某种原因没有提取任何字符(甚至没有丢弃的分隔符),getline设置failbit并返回。

My question is how does one deal with this behavior, where you want your stream to catch a failbit exception for all cases except the one caused by reaching the eof , of a file with an empty last line. 我的问题是如何处理这种行为,你希望你的流为所有情况捕获一个failbit异常,除了由于到达eof而导致的最后一行空文件。 Is there something obvious that I am missing? 有什么明显的东西让我失踪吗?

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

where example.txt is a tab-delimited file, with its last line being only the \\n char: 其中example.txt是制表符分隔的文件,其最后一行只是\\n char:

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

EDIT: 编辑:

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

Edit: I misunderstood the OP, refer to David's answer above. 编辑:我误解了OP,请参阅David的上述答案。 This answer is for checking whether or not the file has a terminating newline. 此答案用于检查文件是否具有终止换行符。

At the end of your while (getline) loop, check for file.eof() . while (getline)循环结束while (getline) ,检查file.eof()

Suppose you just did std::getline() for the last line in the file. 假设你刚刚为文件的最后一行做了std::getline()

  • If there is a \\n after it, then std::getline() has read the delimiter and did not set eofbit . 如果后面有\\n ,那么std::getline()已经读取了分隔符并且没有设置eofbit (In this case, the very next std::getline() will set eofbit .) (在这种情况下,下一个std::getline()将设置eofbit 。)

  • Whereas if there is no \\n after it, then std::getline() has read EOF and did set eofbit . 然而,如果它之后没有\\n ,那么std::getline()已经读取了EOF并且确实设置了eofbit

In both cases, the very next std::getline() will trigger failbit and enter your exception handler. 在这两种情况下,下一个std::getline()将触发failbit并输入您的异常处理程序。

PS: the line if ((line[0] != comment) && (line.size() != 0)) { is UB if line is empty. PS:行if ((line[0] != comment) && (line.size() != 0)) {如果line为空则为UB。 The conditions' order needs to be reversed. 条件的顺序需要颠倒。

Another way to avoid setting failbit , is simply to refactor your if tests to detect the read of an empty-line . 避免设置failbit另一种方法是简单地重构if测试以检测空行的读取。 Since that is your final line in this case, you can simply return to avoid throwing the error, eg: 由于这是你在这种情况下的最后一行,你可以简单地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
            }
        }
    }
    ...

You other alternative is to check whether eofbit is set in catch . 另一种方法是检查eofbit是否设置为catch If eofbit is set -- the read completed successfully. 如果设置了eofbit - 读取成功完成。 Eg 例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM