简体   繁体   中英

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

Imagine you have the following in 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. Or imagine you write to a USB flash drive and the device is withdrawn and re-inserted during the writing process.

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.

I don't think that is something you can detect at the stdio level. 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)

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
  2. Use low-level OS interactions
  3. Verify that IO was successful (if 1 and 2 doesn't work)

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:

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.

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. This is the same way you check if an std::istream read in data to a variable correctly.

However, this is the same as rdstate() , which you say you tried. 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. 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. I can't find such a guarantee for std::ostream s.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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