提问人:Steve Summit 提问时间:8/9/2014 最后编辑:CommunitySteve Summit 更新时间:8/9/2014 访问量:2931
fstream EOF 意外抛出异常
fstream EOF unexpectedly throwing exception
问:
我的问题与上一个问题非常相似。我想打开并读取一个文件。如果文件无法打开,我希望抛出异常,但我不希望在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;
}
}
但它不起作用,因为使用 operator>> 的基本 fstream 读取显然是 EOF 设置坏位或失败位的操作之一。如果文件存在且不包含“foo”,则该函数不会根据需要返回 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);
在打开之前或之后,抛出异常,以防在读取过程中发生非常糟糕的事情。
评论
ifs.open
e.what()
throw std::exception(strerror(errno));
当文件到达末尾时尝试提取时,也会设置该标志,这是流的布尔运算符的行为所允许的。您应该设置一个额外的 try-catch 块,如果它与文件结束条件不对应,则重新引发异常:std::ios_base::failbit
f()
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;
评论
while(ifs >> word) { ... }
while(true) { try { if(!(ifs >> word)) break; } catch (...) { ... } ...
basic_ios::operator bool()
检查 ,而不是 .在达到 EOF 后,您的循环会尝试再读一个单词。 如果未提取任何字符,则设置。这就是为什么你总是在有例外的情况下退出。fail()
!good()
operator>>(stream&, string&)
failbit
不过,这很难避免。流不是在读取最后一个字符时达到 EOF 状态,而是在尝试读取最后一个字符时达到 EOF 状态。如果这发生在单词的中间,则未设置。如果它发生在开头(例如,如果输入有尾随空格),则设置为。你不可能真正可靠地最终进入状态。failbit
failbit
eof() && !fail()
评论