std::getline 在遇到 eof 时抛出

Posted

技术标签:

【中文标题】std::getline 在遇到 eof 时抛出【英文标题】:std::getline throwing when it hits eof 【发布时间】:2012-08-02 05:10:08 【问题描述】:

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

【问题讨论】:

旁注:循环的结构不正确,因为您需要在std::getline() 之后立即检查eof() 您要求例外。点击eof 后,流处于bad 状态。 Why is iostream::eof inside a loop condition considered wrong? '如何处理这种情况'。这取决于你想做什么,你没有很好地解释自己。你不想有例外吗?你想捕捉异常吗?如果你想捕捉它,接下来你想发生什么?请解释您要做什么。 【参考方案1】:

您在代码的最开头激活流的异常处理:

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

现在如果浮点值、整数或字符串等格式化数据的提取失败,它将设置失败位:

eofbit 表示输入操作已到达结束
          输入序列;
failbit 表示输入操作未能读取预期的
          字符,或输出操作未能生成
          想要的字符。

虽然getline(stream,buffer) 确实会在到达文件末尾时设置eofbit,但它也会设置故障位,因为无法提取所需的字符(一行)。

要么在循环周围包装另一个 try-catch-block,要么禁用 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
错误位是:
故障位:1
eofbit: 1
坏比特:0

请注意,两者 eofbitfailbit 均已设置。

另见:

std::ios_base::iostate 第 27.5.3.1.5 节中的表 124(见上文)

【讨论】:

那么我应该在getline 周围放置一个静默catch 块吗? 如果你使用getline(std::istream,std::string),那么它无法提取字符串的唯一原因就是EOF。我建议您实际上禁用在std::ifstream::failbit 上引发异常。当然,您可以使用静默 catch 块。处理这类事情的方法有很多,选择最适合自己的。 我希望getline 将流读入缓冲区,只要它不获取eof. once it fails due to eof` 我希望控件低于getline,因为我有前几行的状态保留以前的迭代。【参考方案2】:

如您所说,当流当前位于文件末尾的空白行时调用 getline 将同时设置 eofbit(因为它到达文件末尾)和 failbit(因为无法提取任何内容,甚至行分隔符)。

因此,如果您已将流设置为在设置 failbit 时引发异常,则在读取该空白行时会引发异常。

为了防止这种情况,您可以在调用 getline 之前查看流中的下一个字符:

std::string buffer = "";
while(stream.peek() != EOF && std::getline(stream, buffer))
    //do something with the buffer

【讨论】:

以上是关于std::getline 在遇到 eof 时抛出的主要内容,如果未能解决你的问题,请参考以下文章

检查 string::getline 中的 eof

std::getline() 返回

我在 Flutter 中遇到了一个问题:在构建 TextField 时抛出了以下断言,它使我遇到了一个奇怪的问题

为啥 Java 7 Files.walkFileTree 在远程驱动器上遇到 tar 文件时抛出异常

std::getline() 不会忽略空格

为啥 FtpWebRequest 恰好在长传输结束时抛出 WebException?