当std::getline遇到文件结束符时会抛出异常

12

std::getline在遇到eof时会抛出异常。这是我的做法。

std::ifstream stream;
stream.exceptions(std::ifstream::failbit|std::ifstream::badbit);
try{
  stream.open(_file.c_str(), std::ios_base::in);
}catch(std::ifstream::failure e){
  std::cout << "Failed to open file " << _file.c_str() << " for reading" << std::endl;
}
while(!stream.eof()){
  std::string buffer = "";
  std::getline(stream, buffer);
  //process buffer
  //I do also need to maintain state while parsing
}
在上述代码中,getline由于读取到eof而抛出异常。如何处理这种情况?

编辑

std::string buffer = "";
while(std::getline(stream, buffer)){
    //also causes getline to hit eof and throw
}

1
旁注:循环的结构不正确,因为您需要立即在执行std::getline()后检查eof() - hmjd
3
你正在请求一个例外。在到达“EOF”(文件结束)后,流处于“bad”状态。 - Bo Persson
3
为什么在循环条件中使用iostream::eof被认为是错误的? - Xeo
如何处理这种情况。这取决于你想做什么,你没有解释清楚。你想不出现异常吗?你想捕获异常,如果你想捕获它,下一步你想发生什么?请解释一下你想做什么。 - jahhaj
2个回答

15

你可以在代码开头处启用流的异常处理:

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

现在,如果提取格式化数据(如浮点数、整数或字符串)失败,它将设置failbit:

eofbit 指示输入操作到达了输入序列的末尾;
failbit 指示输入操作未能读取预期的字符,或者输出操作未能生成所需的字符。

虽然getline(stream,buffer)确实会设置eofbit,但如果无法提取所需的字符(一行),它也会设置failbit。

要么在循环周围再包裹一个try-catch块,要么禁用failbit异常。

例子:

#include <iostream>
#include <fstream>

int main(){
  std::ifstream stream("so.cc");
  stream.exceptions(std::ifstream::failbit|std::ifstream::badbit);
  std::string str;

  try{
    while(std::getline(stream, str));
  }catch(std::ifstream::failure e){
    std::cerr << "Exception happened: " << e.what() << "\n"
      << "Error bits are: "
      << "\nfailbit: " << stream.fail() 
      << "\neofbit: " << stream.eof()
      << "\nbadbit: " << stream.bad() << std::endl;    
  }
  return 0;
}

结果:

发生异常:basic_ios::clear
错误位如下:
failbit: 1
eofbit: 1
badbit: 0

请注意,两个标志都被设置为eofbitfailbit

另请参阅:


我应该在 getline 周围放置一个空的 catch 块吗? - Dipro Sen
1
如果您使用getline(std::istream,std::string),那么它无法提取字符串的唯一原因将是EOF。我建议您实际上禁用std::ifstream::failbit上的异常抛出。当然,您可以使用一个静默的catch块。有许多处理此类事情的方法,请选择最适合您的方法。 - Zeta
我希望getline将流读入缓冲区,只要它没有获取到eof。一旦由于eof而失败,我希望控制权转移到getline下面,因为我保留了先前迭代的行的状态。 - Dipro Sen

2
正如您所说,当流当前位于文件末尾的空白行时调用getline将设置eofbit(因为它到达文件末尾)和failbit(因为无法提取任何内容,甚至不是行分隔符)。
因此,如果您已将流设置为在设置failbit时抛出异常,则在读取该空白行时会抛出异常。
为了防止这种情况发生,您可以在调用getline之前对流进行下一个字符的预读:
std::string buffer = "";
while(stream.peek() != EOF && std::getline(stream, buffer)){
    //do something with the buffer
}

用这种方法没有运气;即使在查看之后,我仍然遇到异常。 - GuyPaddock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接