fstream EOF异常抛出

fstream EOF unexpectedly throwing exception

本文关键字:异常 EOF fstream      更新时间:2023-10-16

我的问题与上一个问题非常相似。我想打开并读取一个文件。我希望在文件无法打开时抛出异常,但我不希望在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读取显然是EOF设置坏位或失败位的操作之一。如果文件存在且不包含"foo",则该函数不会按预期返回false,而是抛出异常。

当文件到达末尾时试图提取时,也会设置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;

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

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);

之前或之后打开,以抛出异常,以防在读取过程中发生非常糟糕的事情。

basic_ios::operator bool()检查fail(),不检查!good()。在达到EOF后,循环尝试再读取一个单词。如果没有提取字符,operator>>(stream&, string&)将设置failbit。这就是为什么你总是用一个异常退出。

这是很难避免的。流到达EOF状态不是在读取最后一个字符时,而是在尝试读取超过最后一个字符时。如果这发生在单词的中间,则没有设置failbit。如果它发生在开头(例如,如果输入末尾有空格),则设置failbit。你不可能真正可靠地结束在eof() && !fail()状态