在写入数据时,std::ofstream中的错误处理

20

我有一个小程序,其中我初始化了一个字符串并将其写入文件流:

#include<iostream>
#include<fstream>
using namespace std;
int main()
{
  std::ofstream ofs(file.c_str());
  string s="Hello how are you";
  if(ofs)
     ofs<<s;
  if(!ofs)
  {
       cout<<"Writing to file failed"<<endl;
  }
  return 0;
 }

我的磁盘空间非常少,语句 "ofs<" 失败了。所以我知道这是一个逻辑错误。

语句 "if(!ofs)" 没有遇到上述问题,因此我无法知道它为什么失败了。

请告诉我,还有哪些选项可以让我知道 "ofs<" 已经失败。

提前感谢。


如果 ofstream::operator<< 失败,它将修改内部状态标志。你是否检查过 ofstream::eof/bad/fail - emlai
@zenith:如果打开文件失败,内部状态标志将会改变。请问在写入时也发生失败了吗?如果可能的话,请展示一些代码。 - Santosh Sahu
@zenith 如果在尝试写入数据时发生写入错误,ofstream::operator<< 将失败。由于缓冲,通常不会在输出操作上失败。通常情况下,在 close 之后验证 ofstream 的状态就足够了(此时保证所有数据都已刷新);如果您需要及时检查,则必须先刷新流。 - James Kanze
@zenith 嗯,它并没有明确指出错误的含义。缓冲很容易导致错误状态被推迟。 - James Kanze
顺便说一下:验证输出是否成功确实是通用输出中最基本的元素之一。教程如果不坚持在关闭后至少检查输出流,则非常不足。 - James Kanze
显示剩余3条评论
2个回答

25

原则上,如果出现写入错误,badbit 应该被设置。然而,由于缓冲的存在,错误只有在流实际尝试写入时才会设置,因此可能会在比错误发生时间更晚的写入或甚至关闭之后才被设置。此外,这个标志是“黏性”的,所以一旦设置,它将保持设置状态。

鉴于上述情况,通常的做法是在关闭流后验证输出的状态;当输出到 std::coutstd::cerr 时,在最终刷新后进行。类似于:

std::ofstream f(...);
//  all sorts of output (usually to the `std::ostream&` in a
//  function).
f.close();
if ( ! f ) {
    //  Error handling.  Most important, do _not_ return 0 from
    //  main, but EXIT_FAILUREl.
}
当向std::cout输出时,将f.close()替换为std::cout.flush()(当然,要加上if (! std::cout))。
并且:这是标准程序。 当发生写入错误时返回代码为0(或EXIT_SUCCESS)的程序是不正确的。

你关于EXIT_FAILURE的声明是否意味着程序在写入错误后继续运行是不安全的?我认为这是不安全的,但我只是想更加确定。 - batbrat
1
@batbrat 不,他的意思是当出现问题时,程序不应该返回 0(即成功)。 - n.caillou
2
@n.caillou 很好的观点。当问题发生时,只有在我们完全处理好它的情况下,我们才能返回成功,对吧? - batbrat
2
但是我们如何获取关于写入失败原因的有用信息呢? - kroiz
为什么要用 flush 替换 close? - Boppity Bop

7
我找到了一个类似的解决方案
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
  std::ofstream ofs(file.c_str());
  string s="Hello how are you";
  if(ofs)
     ofs<<s;
  if(ofs.bad())    //bad() function will check for badbit
  {
       cout<<"Writing to file failed"<<endl;
  }
  return 0;
 }

您还可以参考下面的链接这里那里来检查正确性。


7
如果这个方法能够奏效,我会非常惊讶。你必须关闭流或刷新它,才能检测到错误。 - James Kanze
1
当缓冲区写入了大量输入时,是否有可能刷新流?如果是这种情况,那么添加这个检查可能是值得的,以便在注意到错误时程序可以尽快终止。 - batbrat
if (ofs)是什么意思?我本来以为这个条件语句总是成立的,因为ofs是一个栈上的对象。 - jvriesem
2
@jvriesem 可能有点晚了,但是如果在构造函数中无法创建文件 "std::ofstream ofs(file.c_str())",那么对象将为空,并且在 if 语句中进行了检查。 - Cypert
bad() 只检查 badbit,为什么不使用 fail() 呢?它会检查 badbit 和 failbit。 - Build Succeeded

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