在fstream输出操作上执行'catch all'错误检查的正确方法是什么?

时间:2010-04-09 06:55:23

标签: c++ file-io fstream

在向fstream发送数据时检查一般错误的正确方法是什么?

更新:我主要担心的是我听说过输出和物理写入硬盘的任何数据之间的延迟。我的假设是命令“save_file_obj<< save_str”只会将数据发送到某种缓冲区,并且以下检查“if(save_file_obj.bad())”在确定是否存在操作系统时不会有任何用处或硬件问题。我只是想知道在执行任何后续操作(例如关闭程序)之前,将字符串发送到文件并检查以确保将其写入磁盘的最终“全部捕获”方式是什么。

我有以下代码......

int Saver::output()
{
    save_file_handle.open(file_name.c_str());
    if (save_file_handle.is_open())
    {
        save_file_handle << save_str.c_str();

        if (save_file_handle.bad())
        {
            x_message("Error - failed to save file");
            return 0;
        }

        save_file_handle.close();

        if (save_file_handle.bad())
        {
            x_message("Error - failed to save file");
            return 0;
        }

        return 1;
    }
    else
    {
        x_message("Error - couldn't open save file");
        return 0;
    }
} 

3 个答案:

答案 0 :(得分:4)

几点。首先:

save_file_handle

是C ++ fstream实例的糟糕名称。 fstreams不是文件句柄,所有这些都可以使读者感到困惑。

其次,正如迈克尔所说,没有必要将C ++字符串转换为C字符串。您应该真正发现自己这样做的唯一时间是与C风格的APIS接口​​,以及使用一些设计不良的C ++ API,例如(不幸的是)fstream :: open()。

第三,测试流操作是否有效的规范方法是测试操作本身。 Streams转换为void *,这意味着您可以编写如下内容:

if ( save_file_handle << save_str ) {
   // operation worked
}
else {
   // failed for some reason
}

您的代码应始终为testv流操作,无论是输入还是输出。

答案 1 :(得分:2)

收盘后除了支票外的一切似乎都是合理的。也就是说,我会以稍微不同的方式对事物进行重组并抛出异常或使用bool,但这仅仅是一个偏好问题:

bool Saver::output()
{
    std::fstream out(_filename.c_str(),std::ios::out);
    if ( ! out.is_open() ){
         LOG4CXX_ERROR(_logger,"Could not open \""<<filename<<"\"");
         return false;
    }

    out << _savestr << std::endl;
    if ( out.bad() ){
         LOG4CXX_ERROR(_logger,"Could not save to \""<<filename<<"\"");
         out.close();
         return false;
    }

    out.close();
    return true;
}

我还应该指出你不需要使用save_str.c_str(),因为C ++ iostreams(包括fstream,ofstream等)都能输出std :: string对象。此外,如果您在函数范围内构造文件流对象,它将在超出范围时自动关闭。

答案 2 :(得分:2)

您是否完全确定save_file_handle还没有与之关联(打开)的文件?如果确实如此,则调用其open()方法将失败并引发其ios::failbit错误标志 - 如果设置为这样做则会出现任何异常。

除非文件未打开,否则close()方法不会失败,在这种情况下,该方法将引发ios::failbit错误标志。无论如何,析构函数应该关闭文件,如果save_file_handle是代码中的堆栈变量,则自动执行此操作。

int Saver::output()
{
    save_file_handle.open(file_name.c_str());
    if (save_file_handle.fail())
    {
        x_message("Error - file failed to previously close");
        return 0;
    }
    save_file_handle << save_str.c_str();

    if (save_file_handle.bad())
    {
        x_message("Error - failed to save file");
        return 0;
    }    
    return 1;
}

或者,如果您使用ios::exceptions(),则可以将错误检查与文件保存逻辑分开。

int Saver::output()
{
    ios_base::iostate old = save_file_handle.exceptions();
    save_file_handle.exceptions(ios::failbit | ios::badbit);
    try
    {
        save_file_handle.open(file_name.c_str());          
        save_file_handle << save_str.c_str();
    }
    catch (ofstream::failure e)
    {
        x_message("Error - couldn't save file");
        save_file_handle.exceptions(old);
        return 0;
    }
    save_file_handle.exceptions(old);
    return 1;
}

您可能更愿意将save_file_handle.exceptions(ios::failbit | ios::badbit)的调用移至构造函数。然后你可以摆脱重置异常标志的语句。