【问题标题】:Raise I/O error while writing to an unreliable disk in C++在 C++ 中写入不可靠的磁盘时引发 I/O 错误
【发布时间】:2011-12-22 04:19:47
【问题描述】:

假设您在 C++ 中有以下内容:

ofstream myfile;
myfile.open (argv[1]);

if (myfile.is_open()){
 for(int n=0;n<=10;n++){
     myfile << "index="<<n<<endl;
     sleep(1);
 }
}else{
cerr << "Unable to open file";
}

myfile.close();

在写入时,您正在写入的磁盘或介质变得不可用,但在 close() 时又重新打开,这样您之间就会丢失数据。或者想象您写入 USB 闪存驱动器,并且在写入过程中设备被取出并重新插入。你怎么能检测到呢?我尝试检查将写入放入 try {} catch, flags(), rdstate() 中,但到目前为止似乎没有一个工作。

【问题讨论】:

    标签: c++ exception error-handling io writing


    【解决方案1】:
    for(int n=0;n<=10;n++){
        if (!(myfile << "index="<<n<<endl))
            throw std::runtime_error("WRITE FAILED")
        sleep(1);
    }
    

    如果std::ostream 因任何原因失败,它会设置它的状态位,然后检查std::stream 是否处于布尔上下文中。这与检查std::istream 是否正确将数据读入变量的方法相同。

    但是,这与您说您尝试过的rdstate() 相同。如果是这种情况,则写入已到达缓冲区。刷新程序缓冲区的endl 表明它在操作系统的缓冲区中。从那里,您必须使用特定于操作系统的调用来强制它刷新缓冲区。

    [编辑] 根据http://msdn.microsoft.com/en-us/library/17618685(v=VS.100).aspx,如果您有文件描述符,您可以使用_commit 强制刷新。我找不到std::ostreams 这样的保证。

    【讨论】:

    • 我写了但没有提出任何内容: if (!(myfile
    • @madreblu:这意味着文件在操作系统内存中,在您的程序之外。我仍在试图弄清楚如何强制刷新,而不是填充 RAM。你的目标操作系统是什么?还是您的目标是便携?
    • 我写了“我的文件
    • @madreblu:尝试致电std::ostream::pubsync() 看看是否可行。可能,但我对此表示怀疑。
    • @madreblu:对于 Linux:您的流有 fstream::filedesc()fstream::rdbuf()-&gt;fd() 成员吗?如果是这样,请给他们打电话_commit(...),那可能会这样做。或者,如果您有一个 fstream::sync() 也可能有用。
    【解决方案2】:

    恕我直言,您可以尝试:

    1. 使用ios:exceptions
    2. 使用低级操作系统交互
    3. 验证 IO 是否成功(如果 1 和 2 不起作用)

    【讨论】:

    • 1:试过了,看看我对 Eric 的回答 2-3 的评论:比如什么?
    • @madreblu,2 是特定于操作系统的,您应该深入了解文档。 3 - 尝试阅读您所写的内容并验证它是否匹配。您可以使用一些校验和或哈希算法,如 MD5、SHA 或 CRC。
    【解决方案3】:

    我不确定这是否会涵盖您的场景(在写入过程中移除 USB 驱动器),但您可以尝试在流上启用例外:

    myfile.exceptions(ios::failbit | ios::badbit);
    

    根据我的经验,iostreams 在使检测错误和错误类型变得困难方面做得“很棒”。

    【讨论】:

    • 他说他正在检查 rdstate,这将触发与那些异常相同的事情,因此这些异常不会被触发。
    • 代码现在是这样,但仍然说 rdstate 是 goodbit : myfile.exceptions ( ofstream::failbit | ofstream::badbit ); myfile.open (argv[1]); if (myfile.is_open()){ for(int n=0;n
    【解决方案4】:

    我不认为这是您可以在 stdio 级别检测到的东西。通常,当硬盘驱动器暂时停止响应时,操作系统会自动重试命令,直到它们成功或达到超时,此时您的系统调用可能会收到错误。 (OTOH 可能不会,因为您的调用可能已经返回,在数据写入内存文件系统缓存之后但在任何命令发送到实际磁盘之前)

    如果您真的想检测易碎硬盘,您可能需要将代码编写到低得多的级别,例如编写自己的硬件驱动程序。

    【讨论】:

    • 写U盘,写过程中设备退出了怎么办?
    猜你喜欢
    • 1970-01-01
    • 2018-05-12
    • 2015-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-21
    相关资源
    最近更新 更多