Search code examples
c++fstream

fstream !fail() and is_open()


I want to write data to a file via fstream and output if completely (open-write-close) successful or not. I want also to write as few code as possible. It's about C++03.

Solution1 (seems optimal):

std::fstream file;
file.open("test.txt",std::ios_base::out); // sets failbit to true if open fails?
file << data; // what happens here if !file.is_open()?
file.close(); // and here? does close() work when writing data failed?
if (file)
    std::cout << "Success";
else
    std::cout << "Failed";

file.clear(); // for again usage. But what happens if file failed to open?
              // Or data failed to be written? Or file failed to be closed?
              // Is data waiting in stream to be written to next opened file?

Solution2:

std::fstream file;
file.open("test.txt",std::ios_base::out);
if (file.is_open())
{
    file << data;
    file.close();
}
if (file) // if only writing data fails, is failbit reset by close()?
    std::cout << "Success";
else
    std::cout << "Failed";

file.clear();

Solution3:

// is this solution overkill?

std::fstream file;
file.open("test.txt",std::ios_base::out);
if (file.is_open())
{
    file << data;
    if (!file)
    {
        std::cout << "Failed";
        file.clear();
    }
    file.close();
    if (file)
        std::cout << "Success";
    else
        std::cout << "Failed (again)";
}
else
    std::cout << "Failed";

file.clear();

Are they all equivalent and safe?


Solution

  • Any solution will actually be fairly complicated, because you'll normally want to handle different types of errors differently. If you cannot open the file, for example, you want to tell the user that, and not just that the output failed. Not being able to open the file is an error that you really expect. On the other hand, if a write operation fails, you want a different error handling.

    Thus, I would recommend checking is_open immediately after trying to open the file, and handling the error appropriately then.

    Later errors are far rarer, but probably more serious. In many cases, it's acceptable to only check for the error after the close, but whenever an error occurs, you should probably delete the partially written (and thus corrupt) file. The same holds if your program fails for some other reason when writing the data: close the file and delete it. (I tend to use an RAII class for this, with a commit function which is called when all of the output has finished. The commit closes the file, and if the close succeeds, sets a flag; if the flag is not set when the destructor is called, the destructor closes the file, ignoring any errors, and then deletes it.)

    As for using clear(): I can't think of a case where I'd use it on an output stream. The iostream classes aren't designed for reuse, and have far too much internal state to be easily reset. On input, it can be useful, followed by ignore, if there was a format error, but this consideration doesn't apply to output streams, so I'd just ignore it. (And of course, once you call clear, you have no way of knowing whether anything which preceded it succeeded or not.)