Why ofstream would fail to open the file in C++? Reasons?
Too many file handles open? Out of space? Access denied? Intermittent network drive problem? File already exists? File locked? It's awfully hard to say without more details. Edit: Based on the extra details you gave, it sounds like you might be leaking file handles (opening files and failing to close them and so running out of a per-process file handle limit).
I assume that you're familiar with using the exceptions
method to control whether iostream
failures are communicated as exceptions or as status flags.
In my experience, the iostream
classes give very little details on what went wrong when they fail during an I/O operation. However, because they're generally implemented using lower-level Standard C and OS API functions, you can often get at the underlying C or OS error code for more details. I've had good luck using the following function to do this.
std::string DescribeIosFailure(const std::ios& stream)
{
std::string result;
if (stream.eof()) {
result = "Unexpected end of file.";
}
#ifdef WIN32
// GetLastError() gives more details than errno.
else if (GetLastError() != 0) {
result = FormatSystemMessage(GetLastError());
}
#endif
else if (errno) {
#if defined(__unix__)
// We use strerror_r because it's threadsafe.
// GNU's strerror_r returns a string and may ignore buffer completely.
char buffer[255];
result = std::string(strerror_r(errno, buffer, sizeof(buffer)));
#else
result = std::string(strerror(errno));
#endif
}
else {
result = "Unknown file error.";
}
boost::trim_right(result); // from Boost String Algorithms library
return result;
}
Detecting reason for failure to open an ofstream when fail() is true
Unfortunately, there is no standard way of finding out exactly why open() failed. Note that sys_errlist is not standard C++ (or Standard C, I believe).
Does std::ofstream guarantee the old open file will be closed if opening new one?
The second and subsequent calls will fail.
[filebuf.members]
basic_filebuf* open(const char* s, ios_base::openmode mode);
2 Effects: Ifis_open() != false
, returns a null pointer. Otherwise...
[ofstream.members]
void open(const char* s, ios_base::openmode mode = ios_base::out);
3 Effects: Callsrdbuf()->open(s, mode | ios_base::out)
. If that function does not return a null pointer callsclear()
, otherwise callssetstate(failbit)
fstream !fail() and is_open()
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 callclear
, you have no way of knowing whether anything which
preceded it succeeded or not.)
Related Topics
Convert Std::Variant to Another Std::Variant with Super-Set of Types
Why Is It a Compile Error to Assign the Address of an Array to a Pointer "My_Pointer = &My_Array"
Create Shared_Ptr to Stack Object
How to Run Only One Instance of Application
Nested Class' Access to Enclosing Class' Private Data Members
What Are the Advantages and Disadvantages of Implementing Classes in Header Files
Debug Assertion Failed! Expression: _Block_Type_Is_Valid
Cmake Link Library Target Link Error
Why Does Adding 0 to the End of Float Literal Change How It Rounds (Possible Gcc Bug)
Element Count of an Array in C++
Use Const Wherever Possible in C++
Can't Access Derived Class Method from Pointer of Type Base Class
Why Isn't Operator Overloading for Pointers Allowed to Work
Potential Problem in "Swapping Values of Two Variables Without Using a Third Variable"