简体   繁体   English

在 C++ 中写入不可靠的磁盘时引发 I/O 错误

[英]Raise I/O error while writing to an unreliable disk in C++

Imagine you have the following in C++:想象一下,您在 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();

And while writing, the disk or medium you are writing to becomes unavailable but comes back on for the close() so that you have missing data in between.在写入时,您正在写入的磁盘或介质变得不可用,但会在close()时重新打开,因此您之间会丢失数据。 Or imagine you write to a USB flash drive and the device is withdrawn and re-inserted during the writing process.或者想象您写入 USB 闪存驱动器,并且在写入过程中设备被取出并重新插入。

How can you detect that ?你怎么能检测到呢? I tried checking putting the write in try {} catch , flags() , rdstate() , you name it, but none thus far seem to work.我尝试检查将写入放入try {} catchflags()rdstate() ,你的名字,但到目前为止似乎没有一个工作。

I don't think that is something you can detect at the stdio level.我不认为这是您可以在 stdio 级别检测到的东西。 Typically when a hard drive temporarily stops responding, the operating system will automatically retry the commands either until they succeed or a timeout is reached, at which point your system call may receive an error.通常,当硬盘驱动器暂时停止响应时,操作系统会自动重试命令,直到它们成功或达到超时,此时您的系统调用可能会收到错误。 (OTOH it may not, because your call may have returned already, after the data was written into the in-memory filesystem cache but before any commands were sent to the actual disk) (OTOH可能不会,因为您的调用可能已经返回,在数据写入内存文件系统缓存之后但在任何命令发送到实际磁盘之前)

If you really want to detect flakey hard drive, you'll probably need to code to a much lower level, eg write your own hardware driver.如果你真的想检测易碎的硬盘驱动器,你可能需要编写低得多的代码,例如编写你自己的硬件驱动程序。

IMHO you can try to:恕我直言,您可以尝试:

  1. Use ios:exceptions使用ios:异常
  2. Use low-level OS interactions使用低级操作系统交互
  3. Verify that IO was successful (if 1 and 2 doesn't work)验证 IO 是否成功(如果 1 和 2 不起作用)

I'm not sure if this will cover your scenario (removing a USB drive mid-write), but you can try enabling exceptions on the stream:我不确定这是否会涵盖您的场景(在写入过程中移除 USB 驱动器),但您可以尝试在流上启用例外:

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

In my experience, iostreams do a "great" job of making it hard to detect errors and the type of error.以我的经验,iostreams 在使检测错误和错误类型变得困难方面做得“很棒”。

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

If the std::ostream fails for any reason, it sets it's state bit, which is checked then the std::stream is in a boolean context.如果std::ostream由于任何原因失败,它会设置它的状态位,然后检查std::stream是否处于布尔上下文中。 This is the same way you check if an std::istream read in data to a variable correctly.这与检查std::istream是否正确将数据读入变量的方法相同。

However, this is the same as rdstate() , which you say you tried.但是,这与您说您尝试过的rdstate()相同。 If that's the case, the write has gotten to a buffer.如果是这种情况,则写入已到达缓冲区。 endl , which flushes the programs buffer, shows that it's in the Operating System's buffer. endl刷新程序缓冲区,表明它在操作系统的缓冲区中。 From there, you'll have to use OS-specific calls to force it to flush the buffer.从那里,您必须使用特定于操作系统的调用来强制它刷新缓冲区。

[Edit] According tohttp://msdn.microsoft.com/en-us/library/17618685(v=VS.100).aspx , you can force a flush with _commit if you have a file descriptor. [编辑] 根据http://msdn.microsoft.com/en-us/library/17618685(v=VS.100).aspx ,如果您有文件描述符,您可以使用_commit强制刷新。 I can't find such a guarantee for std::ostream s.我无法为std::ostream找到这样的保证。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM