3

将数据发送到 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;
    }
} 
4

3 回答 3

5

几点。首先:

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
}

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

于 2010-04-09T08:42:46.287 回答
4

除了收盘后的检查外,一切似乎都是合理的。也就是说,我会稍微改变结构并抛出异常或使用 a bool,但这只是一个偏好问题:

bool Saver::output()
{
    std::fstream out(_filename.c_str(),std::ios::out);
    如果(!out.is_open()){
         LOG4CXX_ERROR(_logger,"无法打开\""<<文件名<<"\"");
         返回假;
    }

    出 << _savestr << std::endl;
    如果(out.bad()){
         LOG4CXX_ERROR(_logger,"无法保存到\""<<文件名<<"\"");
         out.close();
         返回假;
    }

    out.close();
    返回真;
}

我还应该指出,您不需要使用save_str.c_str(),因为 C++ iostream(包括 fstream、ofstream 等)都能够输出 std::string 对象。另外,如果在函数作用域内构造文件流对象,超出作用域时会自动关闭。

于 2010-04-09T08:15:08.673 回答
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)构造函数。然后,您可以摆脱重置异常标志的语句。

于 2010-04-09T08:41:33.017 回答