2

I want to write a wrapper around fstream class. As I can see the most common way to check if stream works well is to see result of good() function. However, I've heard that this is mostly historical function and it is not really safe to use it (to be more correct, there may be some situations when stream doesn't work well but function returns true. So I'd like to share experience and to know from others what is the most correct way to check fstream for errors.

It would be great if there could be a possibility to check different types of errors like if file doesn't exist, can be opened only for reading, etc. It is also necessary to leave such programs to be crossplatform (however, the main target is Linux).

Thanks in advance!

ghostmansd
  • 3,285
  • 5
  • 30
  • 44
  • Do you just want to know about opening the file? Or reading/writing it too? – doctorlove Jul 05 '13 at 14:32
  • @doctorlove Yes, it would be great to know about reading/writing too. I know how to read/write files with (at least with C++), but I'd like to catch all bad things which may happen and throw my own exceptions depending on kind of errors. – ghostmansd Jul 05 '13 at 14:34

3 Answers3

1

If a file operation fails, and eof() returns false then you could check errno or GetLastError (depending on platform) to find out what's wrong.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I've heard that some realisations don't throw exceptions. As I think, that may be not enough. – ghostmansd Jul 05 '13 at 14:46
  • @ghostmansd None of the C++ stream functions throw exceptions. You have to have checks for failures in your code at every point. – Some programmer dude Jul 05 '13 at 14:50
  • Correct me, please, if I'm wrong: we have to check `eof()`, `fail()` and `!operator()` member functions, then we have to check system (probably using macros like in `predef` project, then we have to check code using `errno` or `GetLastError()` depending on platform. As I suppose on Linux I can use `man errno.h` to see error codes. What about Windows? I've found [this page](http://msdn.microsoft.com/en-us/library/ms681381(v=vs.85).aspx), but it contains really a lot of codes, probably you know a place where I can find codes which are about file processing? – ghostmansd Jul 05 '13 at 15:14
  • Check [this](http://stackoverflow.com/questions/8241792/finding-end-of-file-while-reading-from-it/8242142#8242142) and [this](http://stackoverflow.com/questions/164344/how-do-i-read-a-text-file-from-the-second-line-using-fstream/164694#164694) questions too. They only affirm everything what you, MasterHD and I have said. – ghostmansd Jul 05 '13 at 15:26
1

I only really have 2 suggestions, and they both rely on checking the opened stream with the returned value of the overloaded ! operator. Use input-only mode, to simply check if the file exists:

char name[] = "C:\\some_folder\\some file.txt";
std::ifstream f;
f.open(name, std::ios::in);
if (!f)
    printf("File does not exist, or inadequate permissions");
f.close();

Open with in/out mode to prevent it from being truncated when you're planning to perform write operations:

std::fstream f;
f.open(name, std::ios::in | std::ios::out);
if (!f)
    printf("Could not open file");
f.close();

By default, those are the input parameters for the respective streams, but I've explicitly shown them for clarification.

During read/write operations to check for eof, etc., the first answer to this question looks insightful.

Community
  • 1
  • 1
MasterHD
  • 2,264
  • 1
  • 32
  • 41
  • 2
    Failing to open the file may not mean that the file doesn't exist, it could be that the current user have no right to read/write the file. Also, the flags is nit needed, `std::ios::in` is the default for `std::ifstream`, similar with `std::fstream` and `std::ofstream`, the correct flags are default. – Some programmer dude Jul 05 '13 at 14:56
  • NB: It may be a good idea to write "C:\\some_folder\\some_file.txt" instead of "C:\\some_folder\\some_file.txt" even on WIndows. – ghostmansd Jul 05 '13 at 15:15
  • @ghostmansd Took me a while to realize the only difference was removing the underscore. Done – MasterHD Jul 05 '13 at 18:00
  • The ios::in is not the default, it is implied. That means that even if you don't supply it to an ifstream, you still get it, so writing it is IMHO useless. Further, I'd like to add that you don't have to call open() separately, you can initialize the stream with those parameters. – Ulrich Eckhardt Jul 06 '13 at 07:48
0

good()/bad() test only the badbit, which covers only some, and mostly unrecoverable errors. To check for errors you need to check both failbit and badbit. See iosstate for more details on when these bits are set.

To check for errors, use fail(), which checks both failbit and badbit:

  if (stream.fail()) { /* handle error ... */ }

C++ streams also overload operator bool to return !fail(), so you can simply do

  if (!stream) { /* handle error ... */ }

Then you can get the last error from errno and convert it to text with strerror():

  std::ifstream f("my_file");
  if (!f) {
      std::cerr << std::strerror(errno) << std::endl;
      return 1;
  }

Note that failbit includes eofbit (in the sense that attempting to read at EOF will set both bits), so to check for read errors you need to exclude eofbit:

  std::string line;
  while (std::getline(f, line)) {
      // process line
  }
  if (!f && !f.eof()) {
      std::cerr << std::strerror(errno) << std::endl;
  }
rustyx
  • 80,671
  • 25
  • 200
  • 267