fstream EOF出乎意料地抛出异常

时间:2014-08-08 23:11:36

标签: c++ exception fstream eof

我的问题与a previous one非常相似。我想打开并读取一个文件。如果无法打开文件,我想要抛出异常,但我不希望在EOF上抛出异常。 fstreams似乎可以让你独立控制是否在EOF,失败和其他坏事上抛出异常,但看起来EOF往往也会映射到坏的和/或失败的异常。

这是我试图做的一个精简的例子。如果文件包含某个单词,则函数f()应返回true,否则返回false,如果(例如)该文件不存在则抛出异常。

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

using namespace std;

bool f(const char *file)
{
    ifstream ifs;
    string word;

    ifs.exceptions(ifstream::failbit | ifstream::badbit);
    ifs.open(file);

    while(ifs >> word) {
        if(word == "foo") return true;
    }
    return false;
}

int main(int argc, char **argv)
{
    try {
        bool r = f(argv[1]);
        cout << "f returned " << r << endl;
    } catch(...) {
        cerr << "exception" << endl;
    }
}

但它不起作用,因为使用运算符的基本fstream读取&gt;&gt;显然是EOF设置坏或失败位的操作之一。如果文件存在且不包含“foo”,则该函数不会根据需要返回false,而是抛出异常。

3 个答案:

答案 0 :(得分:2)

当文件到达结束时尝试提取时,也会设置std::ios_base::failbit标志,这是流的布尔运算符允许的行为。您应该在f()中设置一个额外的 try-catch 块,如果它与文件结束条件不对应,则重新抛出该异常:

std::ifstream ifs;
std::string word;

ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);

try {
    ifs.open(file);
    while (ifs >> word) {
        if (word == "foo") return true;
    }
 }
catch (std::ios_base::failure&) {
    if (!ifs.eof())
        throw;
}
return false;

答案 1 :(得分:1)

如果目标是仅在打开文件时出现问题时抛出异常,为什么不写:

bool f(const char *file)
{
    ifstream ifs;
    string word;

    ifs.open(file);
    if (ifs.fail())  // throw only when needed 
        throw std::exception("Cannot open file !");  // more accurate exception

    while (ifs >> word) {
        if (word == "foo") return true;
    }
    return false;
}

你当然可以设置:

ifs.exceptions(ifstream::badbit);

在打开之前或之后,如果在阅读过程中发生了非常糟糕的事情,则抛出异常。

答案 2 :(得分:1)

basic_ios::operator bool()检查fail(),而非!good()。在EOF到达后,你的循环尝试再读一个单词。如果未提取任何字符,operator>>(stream&, string&)会设置failbit。这就是为什么你总是以异常退出的原因。

虽然很难避免这种情况。流不会在读取最后一个字符时达到EOF状态,而是在尝试读取最后一个字符时。如果这发生在单词的中间,则不会设置failbit。如果它在开头发生(例如,如果输入具有尾随空格),则设置failbit。您无法真正可靠地以eof() && !fail()州结束。