C++ Ifstream Failbit and Badbit

C++ ifstream failbit and badbit

According to cplusplus.com:

failbit is generally set by an input operation when the error was related to the internal logic of the operation itself, so other operations on the stream may be possible. While badbit is generally set when the error involves the loss of integrity of the stream, which is likely to persist even if a different operation is performed on the stream. badbit can be checked independently by calling member function bad.

In simple words, if you get a number when expect to retrieve a letter, it's failbit. If a serious error happens, which disrupts the ability to read from the stream at all - it's a badbit.

Except mentioned flags there is a third quite similar — eofbit. You can check the state using several functions: ios::fail, ios::good and ios::bad

And you can get familiar with iostream library at MSDN resource too.

Finally, if you search for the correct solution of how to handling all error bits and exceptions while reading from the file (or accessing some file or directory), I highly recommend you read a very comprehensive and well-written article "Reading files in C++ using ifstream: dealing correctly with badbit, failbit, eofbit, and perror()", at the end of which you will find a few Ideal solutions. The article is worth to read indeed.

Does ifstream::close reset failbit and/or badbit?

close() should not clear any of the state flags, although it might set failbit depending on the return value of the underlying buffer.

[fstream.members] (also [ifstream.members] and [ofstream.members])

void close();

Effects: Calls rdbuf()->close() and, if that function returns returns a null pointer, calls setstate(failbit) (27.5.5.4) (which may throw ios_base::failure).

The flags are cleared by open() however, assuming the filebuf opens correctly

void open(const char* s, ios_base::openmode mode =
ios_base::in|ios_base::out);

Effects: Calls rdbuf()->open(s,mode).
If that function does not return a null pointer calls clear(),
otherwise calls setstate(failbit), (which may throw ios_base::failure)
(27.5.5.4).

Why is failbit set when eof is found on read?

Improving @absence's answer, it follows a method readeof() that does the same of read() but doesn't set failbit on EOF. Also real read failures have been tested, like an interrupted transfer by hard removal of a USB stick or link drop in a network share access. It has been tested on Windows 7 with VS2010 and VS2013 and on linux with gcc 4.8.1. On linux only USB stick removal has been tried.

#include <iostream>
#include <fstream>
#include <stdexcept>

using namespace std;

streamsize readeof(istream &stream, char *buffer, streamsize count)
{
if (count == 0 || stream.eof())
return 0;

streamsize offset = 0;
streamsize reads;
do
{
// This consistently fails on gcc (linux) 4.8.1 with failbit set on read
// failure. This apparently never fails on VS2010 and VS2013 (Windows 7)
reads = stream.rdbuf()->sgetn(buffer + offset, count);

// This rarely sets failbit on VS2010 and VS2013 (Windows 7) on read
// failure of the previous sgetn()
(void)stream.rdstate();

// On gcc (linux) 4.8.1 and VS2010/VS2013 (Windows 7) this consistently
// sets eofbit when stream is EOF for the conseguences of sgetn(). It
// should also throw if exceptions are set, or return on the contrary,
// and previous rdstate() restored a failbit on Windows. On Windows most
// of the times it sets eofbit even on real read failure
(void)stream.peek();

if (stream.fail())
throw runtime_error("Stream I/O error while reading");

offset += reads;
count -= reads;
} while (count != 0 && !stream.eof());

return offset;
}

#define BIGGER_BUFFER_SIZE 200000000

int main(int argc, char* argv[])
{
ifstream stream;
stream.exceptions(ifstream::badbit | ifstream::failbit);
stream.open("<big file on usb stick>", ios::binary);

char *buffer = new char[BIGGER_BUFFER_SIZE];

streamsize reads = readeof(stream, buffer, BIGGER_BUFFER_SIZE);

if (stream.eof())
cout << "eof" << endl << flush;

delete buffer;

return 0;
}

Bottom line: on linux the behavior is more consistent and meaningful. With exceptions enabled on real read failures it will throw on sgetn(). On the contrary Windows will treat read failures as EOF most of the times.

ios::exceptions(...) changes when badbit is set

There are 4 distinct stream states (taken from std::ios_base::iostate):

 typedef /*implementation defined*/ iostate;
static constexpr iostate goodbit = 0;
static constexpr iostate badbit = /*implementation defined*/
static constexpr iostate failbit = /*implementation defined*/
static constexpr iostate eofbit = /*implementation defined*/

So setting of the eofbit doesn't necessarily trigger your exception mask.

c++ file bad bit

Quoting the Apache C++ Standard Library User's Guide:

The flag std::ios_base::badbit indicates problems with the underlying stream buffer. These problems could be:

  • Memory shortage. There is no memory available to create the buffer, or the buffer has size 0 for other reasons (such as being provided from outside the stream), or the stream cannot allocate memory for its own internal data, as with std::ios_base::iword() and std::ios_base::pword().
  • The underlying stream buffer throws an exception. The stream buffer might lose its integrity, as in memory shortage, or code conversion failure, or an unrecoverable read error from the external device. The stream buffer can indicate this loss of integrity by throwing an exception, which is caught by the stream and results in setting the badbit in the stream's state.

That doesn't tell you what the problem is, but it might give you a place to start.

Keep in mind the EOF bit is generally not set until a read is attempted and fails. (In other words, checking rifile.good after calling seekg may not accomplish anything.)

As Andrey suggested, checking errno (or using an OS-specific API) might let you get at the underlying problem. This answer has example code for doing that.

Side note: Because rifile is a local object, you don't need to close it once you're finished. Understanding that is important for understanding RAII, a key technique in C++.

ifstream sets failbit on declaration

OK fixed this myself now:

  • Failbit seems to be set by EOFs in some implementations so instead I switched to using input.good() and consequently all was good.
  • There was also some logical error in my program with the checking for "=" part too as ifstream.get() returns it's value as an integer so I needed to cast them back into chars for comparison.


Related Topics



Leave a reply



Submit