Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

fstream and IO errors

42 views
Skip to first unread message

Gert-Jan de Vos

unread,
Jan 23, 2018, 3:54:20 PM1/23/18
to
Whenever I use fstream for file IO, I have to look up the details on
how to detect IO errors like file not found, access violation or disk
full. Sometimes I need to check failbit or badbit, sometimes only
badbit and I can't remember when to choose what.

Ideally I would like to get exceptions with the OS error details
included as proposed in N2503. Unfortunately with MSVC2017
I just get "iostream error" in the exception object.

In an attempt to improve the error message detail level, I
implemented a winfile_streambuf directly on the Win32
CreateFile/ReadFile/WriteFile api's. On an IO error It throws an
exception which includes the os error details. This now works
and improves the file IO error messages, but it wasn't exactly
trivial to implement. This leaves me with a number of questions:

- Is there really no straightforward way to get IO error details
from fstream?

- Is it allowed for an streambuf implementation to throw?

- should my winfile_streambuf differentiate between default
and binary mode? I did this with a textmode_streambuf
adapter.

- My copy of the Josuttis Standard Library book contains one
example of a custom input stream buffer. It calls setg() to
initialize the putback area as empty (eback() == gptr()). Is this
correct? I guess eback() should be less that gptr() to allow for
character putback.

- What is file_streambuf<wchar_t> supposed to do? I guessed
it would read or write a sequence of wchar_t in a file. Yet
std::wofstream produces a file with 8 bit characters, just like
std::ofstream does.

I learned a lot about the iostream architecture during this
exercise but I'm not yet sure if I'm on the right track. I'm
interested to hear on your thoughts or experiences with
iostreams and IO error detection.

cda...@gmail.com

unread,
Jan 23, 2018, 4:19:31 PM1/23/18
to
Based on my limited experience, well, I don't think this is a good idea. Because my last project at work involved helping write a wireless network interface. And based on this gawd awful programming experience, getting the details from the exception object would have been misleading at the very best.

Öö Tiib

unread,
Jan 23, 2018, 5:05:52 PM1/23/18
to
On Tuesday, 23 January 2018 22:54:20 UTC+2, Gert-Jan de Vos wrote:
> Whenever I use fstream for file IO, I have to look up the details on
> how to detect IO errors like file not found, access violation or disk
> full. Sometimes I need to check failbit or badbit, sometimes only
> badbit and I can't remember when to choose what.

Just use ios::fail() to check if one of those is set and look
up actual cause from errno:

std::ifstream f;
f.open(fileName);

if (f.fail())
{
std::cout << "Error: " << strerror(errno) << '\n';
}

The errno is thread-local since C++11 (that added threads
into C++) so it works fine in multi-threaded app as well.

> Ideally I would like to get exceptions with the OS error details
> included as proposed in N2503. Unfortunately with MSVC2017
> I just get "iostream error" in the exception object.

Same there, e.what() tells some vague nonsense not worth reading
and errno is lot better source of information:

std::ifstream f;
std::ios_base::iostate exceptionMask = f.exceptions() | std::ios::failbit;
f.exceptions(exceptionMask);

try
{
f.open(fileName);
}
catch (std::ios_base::failure& e)
{
std::cout << "Vague whine: " << e.what() << '\n';
std::cout << "Error: " << strerror(errno) << '\n';
}

IOW ... TL;DR it is rare case where errno is not sufficient for
diagnosing fstream i/o issues.

Gert-Jan de Vos

unread,
Jan 24, 2018, 3:16:55 AM1/24/18
to
On Tuesday, 23 January 2018 23:05:52 UTC+1, Öö Tiib wrote:
> On Tuesday, 23 January 2018 22:54:20 UTC+2, Gert-Jan de Vos wrote:
> > Whenever I use fstream for file IO, I have to look up the details on
> > how to detect IO errors like file not found, access violation or disk
> > full. Sometimes I need to check failbit or badbit, sometimes only
> > badbit and I can't remember when to choose what.
>
> Just use ios::fail() to check if one of those is set and look
> up actual cause from errno:
>
> std::ifstream f;
> f.open(fileName);
>
> if (f.fail())
> {
> std::cout << "Error: " << strerror(errno) << '\n';
> }

Thank you, this helps. I'm a bit surprised that errno is still the best solution in C++ on Windows. When using exceptions I can only check errno
at the catch site and I run the risk of it being replaced during stack
unwinding.

Öö Tiib

unread,
Jan 24, 2018, 5:21:46 AM1/24/18
to
On Wednesday, 24 January 2018 10:16:55 UTC+2, Gert-Jan de Vos wrote:
> On Tuesday, 23 January 2018 23:05:52 UTC+1, Öö Tiib wrote:
> > On Tuesday, 23 January 2018 22:54:20 UTC+2, Gert-Jan de Vos wrote:
> > > Whenever I use fstream for file IO, I have to look up the details on
> > > how to detect IO errors like file not found, access violation or disk
> > > full. Sometimes I need to check failbit or badbit, sometimes only
> > > badbit and I can't remember when to choose what.
> >
> > Just use ios::fail() to check if one of those is set and look
> > up actual cause from errno:
> >
> > std::ifstream f;
> > f.open(fileName);
> >
> > if (f.fail())
> > {
> > std::cout << "Error: " << strerror(errno) << '\n';
> > }
>
> Thank you, this helps. I'm a bit surprised that errno is still the best solution in C++ on Windows.

It is "typically good enough" C++ with POSIX solution when there
is no need to squeeze out all performance. Best performance on
platforms with virtual memory system (like Windows) are memory
mapped files. Those mean lot of pain compared to fstream for
15%-50% better IO performance.

> When using exceptions I can only check errno
> at the catch site and I run the risk of it being replaced during stack
> unwinding.

That is indeed true when destructors will make calls that can fail
and so set errno. Do not let nonsense like std::ios_base::failure
to fly out of your module that deals with that stream; catch it
in interface and rethrow something better if you want your
functions to throw.
0 new messages