我的问题与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,而是抛出异常。
答案 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()
州结束。