|
| | #1 |
|
Posts: n/a Hébergeur: | So... I'm trying to get used to using C++ ifstream (or ofstream) instead of stdio (although I'm having second thoughts). Anyways, I want to be able to display a meaningful error message if ifstream fails to open a file, but nothing I read about ifstream says anything about a reliable place to get an error message. Using stdio I can simply do: FILE *f = fopen(filename, "rb"); if (!f) perror(filename); So far the best I've been able to do using ifstream is: ifstream f(filename, ios_base::in | ios_base::binary); if (!f.is_open()) cerr << filename << ": tough luck!" << endl; What is a reliable way to get a real error message? Even the example at cplusplus.com: http://www.cplusplus.com/reference/i...m/is_open.html Gives a crappy error message. Thanks, AJ |
|
| | #2 |
|
Posts: n/a Hébergeur: | On Mar 27, 4:29 am, adramo...@gmail.com wrote: > What is a reliable way to get a real error message? Oh, also, related to this, how do I tell if >> fails? Say I am reading 4 integers from an ifstream opened in text mode. Using stdio: int a, b, c, d; if (fscanf(infile, "%i%i%i%i", &a, &b, &c, &d) != 4) fprintf(stderr, "error parsing line\n"); But using ifstream: int a, b, c, d; infile << a << b << c << d; // how to check for failure...? Thanks |
|
| | #3 |
|
Posts: n/a Hébergeur: | On Mar 27, 4:33 am, adramo...@gmail.com wrote: > infile << a << b << c << d; That is, >> |
|
| | #4 |
|
Posts: n/a Hébergeur: | On Mar 27, 1:29pm, adramo...@gmail.com wrote: > So... I'm trying to get used to using C++ ifstream (or ofstream) > instead of stdio (although I'm having second thoughts). Anyways, I > want to be able to display a meaningful error message if ifstream > fails to open a file, but nothing I read about ifstream says anything > about a reliable place to get an error message. Using stdio I can > simply do: > > FILE *f = fopen(filename, "rb"); > if (!f) > perror(filename); > > So far the best I've been able to do using ifstream is: > > ifstream f(filename, ios_base::in | ios_base::binary); > if (!f.is_open()) > cerr << filename << ": tough luck!" << endl; > > What is a reliable way to get a real error message? Even the example > at cplusplus.com: > > http://www.cplusplus.com/reference/i...m/is_open.html The error message has to be your own. Or, you could set up ios::exceptions (for the failure bits you want to associate exceptions with) with your fstream objects. The site above shows samples of how to do that. Using member operator! to test file open failure might make it look easier. For example: ifstream f(filename, ios_base::in | ios_base::binary); if (!f) //no need to call is_open cerr << filename << ": tough luck opening file!" << endl; Failures with fstream objects are notified by setting the following bits: eofbit, failbit and badbit. So, if you want granularity in reporting errors, you would need to check them individually. You would need to go through the documentation of the members of fstream objects to see which operations' failure set which bits. |
|
| | #5 |
|
Posts: n/a Hébergeur: | On 27 Mrz., 09:33, adramo...@gmail.com wrote: [..] > But using ifstream: > > int a, b, c, d; > infile << a << b << c << d; > // how to check for failure...? if ( infile.fail() ) { .... } best, Michael |
|
| | #6 |
|
Posts: n/a Hébergeur: | On Mar 27, 9:29 am, adramo...@gmail.com wrote: > So... I'm trying to get used to using C++ ifstream (or > ofstream) instead of stdio (although I'm having second > thoughts). Anyways, I want to be able to display a meaningful > error message if ifstream fails to open a file, but nothing I > read about ifstream says anything about a reliable place to > get an error message. Using stdio I can simply do: > FILE *f = fopen(filename, "rb"); > if (!f) > perror(filename); Whether that gives you something meaningfull or not depends somewhat on the implementation. What perror outputs depends on errno, and the standard really doesn't specify too much in this regard. > So far the best I've been able to do using ifstream is: > ifstream f(filename, ios_base::in | ios_base::binary); > if (!f.is_open()) > cerr << filename << ": tough luck!" << endl; Why not? ifstream f(filename, ios_base::in | ios_base::binary); if (!f.is_open()) perror( filename ) ; You're very much in the domain of implementation defined, or even unspecified, both with FILE* and ifstream, but in general, I'd expect both of them to behave more or less identically here. (Under Unix, I'm pretty sure they will; errno is set by the functions in the system API which ifstream or fopen must call. They seem to behave the same under Windows as well, at least with VC++.) -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| | #7 |
|
Posts: n/a Hébergeur: | On Mar 27, 9:33 am, adramo...@gmail.com wrote: [...] > int a, b, c, d; > if (fscanf(infile, "%i%i%i%i", &a, &b, &c, &d) != 4) > fprintf(stderr, "error parsing line\n"); > But using ifstream: > int a, b, c, d; > infile << a << b << c << d; > // how to check for failure...? if ( ! infile ) ... You can use an istream as a boolean; it will behave as true if no error has occured, and as false once an error has been seen. Once you've detected an error (and only then), you can use more specific functions to determine the cause: if ( ! infile ) { if ( infile.bad() ) { // Serious hardware problem... (read error, etc.) // A lot of implementations aren't too rigorous // about reporting this, and you might never see // it. } else if ( ! infile.eof() ) { // Format error in the input stream. } else { // Probably an end of file (although in a few rare // cases, infile.eof() can return true even though // there was a format error in the input). } } The error condition is sticky: it must be cleared (function istream::clear()) before you can read further (or do anything else) with the stream. A typical idiom for reading files is: while ( infile >> a >> b >> c ) { // ... } or (more often, because it allows better recovery in case of a format error): std::string line ; while ( std::getline( infile, line ) ) { std::istringstream parse( line ) ; parse >> a >> b >> c >> d >> std::ws ; if ( ! parse || parse.peek() != EOF ) { // Syntax error in the line... } else { // ... } } This has the advantage of not putting the main input in an error state, and leaving it correctly positionned for further reading in case of an error. (Like fscanf, the >> operators treat a new line as white space. So if the input syntax is line oriented, you probably want to use getline to read it, and istringstream to parse each line. Something like you'd use fgets to read and sscanf to parse in C, except that it doesn't require any special handling for excessively long lines.) -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| | #8 |
|
Posts: n/a Hébergeur: | adramolek@gmail.com wrote: > On Mar 27, 4:29 am, adramo...@gmail.com wrote: >> What is a reliable way to get a real error message? > > Oh, also, related to this, how do I tell if >> fails? Say I am reading > 4 integers from an ifstream opened in text mode. Using stdio: > > int a, b, c, d; > if (fscanf(infile, "%i%i%i%i", &a, &b, &c, &d) != 4) > fprintf(stderr, "error parsing line\n"); > > But using ifstream: > > int a, b, c, d; > infile << a << b << c << d; > // how to check for failure...? > > > Thanks if ( infile >> a >> b >> c >> d ) // success else // failure Alternately if ( ! ( infile >> a >> b >> c >> d ) ) // failure else // success -- Jim Langston tazmaster@rocketmail.com |
|
| | #9 |
|
Posts: n/a Hébergeur: | adramolek@gmail.com wrote: > > FILE *f = fopen(filename, "rb"); > if (!f) > perror(filename); > If your machine has perror, it probably has strerror which returns a char* with the same content. |
|
| | #10 |
|
Posts: n/a Hébergeur: | Thanks for your reply. On Mar 27, 6:13 am, James Kanze <james.ka...@gmail.com> wrote: > Whether that gives you something meaningfull or not depends > somewhat on the implementation. What perror outputs depends on > errno, and the standard really doesn't specify too much in this > regard. But, on my system at least, fopen() is documented as setting errno to EINVAL or the various errors caused by malloc() or open(). On the other hand, ifstream is not documented as setting any kind of error flags at all aside from the 3 failure bits that the other people here mentioned. What am I missing? > Why not? > > ifstream f(filename, ios_base::in | ios_base::binary); > if (!f.is_open()) > perror( filename ) ; Because nothing I've read about ifstream mentions errno. Is this valid? For example, with fopen() I know that if it returns NULL errno will be set to something meaningful... at least according to the man page and past experience. However, what guarantees that the ifstream constructor won't do, say, "errno = rand();" before it returns after a failure (what I mean is, does it say somewhere that errno can be relied on after an ifstream fail)? > You're very much in the domain of implementation defined, or > even unspecified, both with FILE* and ifstream, but in general, > I'd expect both of them to behave more or less identically here. > (Under Unix, I'm pretty sure they will; errno is set by the > functions in the system API which ifstream or fopen must call. > They seem to behave the same under Windows as well, at least > with VC++.) Thanks, AJ |
|
| | #11 |
|
Posts: n/a Hébergeur: | On Mar 27, 7:57 am, Ron Natalie <r...@spamcop.net> wrote: > adramo...@gmail.com wrote: > > > FILE *f = fopen(filename, "rb"); > > if (!f) > > perror(filename); > > If your machine has perror, it probably has strerror > which returns a char* with the same content. Thanks for your reply. Mostly what I was wondering about was if ifstream sets errno. |
|
| | #12 |
|
Posts: n/a Hébergeur: | On Mar 27, 4:53 am, Abhishek Padmanabh <abhishek.padman...@gmail.com> wrote: > Using member operator! to test file open failure might make it look > easier. Hey cool, thanks for the tip. > Failures with fstream objects are notified by setting the following > bits: eofbit, failbit and badbit. So, if you want granularity in > reporting errors, you would need to check them individually. I see; this makes sense. It should be enough... mostly I'd like to be able to notify the user about things like "file not found" as opposed to "permission denied", though. Well I guess really those are the two big errors. In the end it's not critical, it's just something I was wondering about. Thanks again, that s a lot AJ |
|
| | #13 |
|
Posts: n/a Hébergeur: | On Mar 27, 6:24 am, James Kanze <james.ka...@gmail.com> wrote: > [a great reply] Thanks a lot! That clears a lot of stuff up. The istringstream is pretty cool, I was wondering if there was something like that. I have one small new question left: Do istreams have anything like scanf's %[] for matching only characters in a set (I think of it like the poor man's regular expression)? It's something I've found pretty handy sometimes in the past. Thanks again, AJ |
|
| | #14 |
|
Posts: n/a Hébergeur: | On Mar 27, 1:46 pm, adramo...@gmail.com wrote: > On Mar 27, 6:24 am, James Kanze <james.ka...@gmail.com> wrote: > I have one small new question left: Do istreams have anything > like scanf's %[] for matching only characters in a set (I > think of it like the poor man's regular expression)? It's > something I've found pretty handy sometimes in the past. No, but unlike scanf, it's totally extensible. I don't think I've ever written an application where we didn't have some user defined extractors or manipulators. Often, too, I'll use something more or less like a decorator (it is a decorator, vis-a-vis iostream), to control input or output in some special way. Just write an extractor which operates indirectly on your string. Alternatively, you don't necessarily need a poor man's replacement. Boost regular expressions works very well, and is in the process of being adopted into the standard. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
| | #15 |
|
Posts: n/a Hébergeur: | On Mar 27, 1:36 pm, adramo...@gmail.com wrote: > On Mar 27, 6:13 am, James Kanze <james.ka...@gmail.com> wrote: > > Whether that gives you something meaningfull or not depends > > somewhat on the implementation. What perror outputs depends on > > errno, and the standard really doesn't specify too much in this > > regard. > But, on my system at least, fopen() is documented as setting errno to > EINVAL or the various errors caused by malloc() or open(). On the > other hand, ifstream is not documented as setting any kind of error > flags at all aside from the 3 failure bits that the other people here > mentioned. What am I missing? That's because your system documents the C API, and doesn't document the C++ one. A function like fopen() is part of the C standard, but also part of the Posix standard, and bundled in the libc which is bundled with the OS. In practice, all that they're doing is documenting the errno values generated by the lower level functions. fopen() doesn't actually set errno itself, ever. And of course ifstream: pen()will eventually call the same low level functions: if you're on a Posix based system, the only way you're going to open a file is with open(), and open() sets errno in case of an error. The only thing that's really going to be different between ifstream: pen() and fopen() is the documentation.> > Why not? > > ifstream f(filename, ios_base::in | ios_base::binary); > > if (!f.is_open()) > > perror( filename ) ; > Because nothing I've read about ifstream mentions errno. Is > this valid? It will definitely work with Unix, unless the implementation is very perverse: Posix also uses errno to report errors from it's low level routines. I did a quick check with VC++ under Windows, and it also worked. (Not too surprising, really. The author of the VC++ standard library played a major role in the standardization of the C library, many years back.) > For example, with fopen() I know that if it returns NULL errno > will be set to something meaningful... at least according to > the man page and past experience. However, what guarantees > that the ifstream constructor won't do, say, "errno = rand();" > before it returns after a failure (what I mean is, does it say > somewhere that errno can be relied on after an ifstream fail)? Common sense? Quality of implementation? I agree that it *should* be documented. But in practice, istream: pen willbehave exactly like fopen. One thing you might want to pay attention to: something like: std::cerr << "the error was: " << errno << std::endl ; may invoke an operator<< before reading errno (which can't happen with the corresponding fprintf). Once you've detected an error, unless you're using a library routine designed to exploit errno, I'd save it in a local variable before anything else. Other than that, it should be business as usual. -- James Kanze (GABI Software) email:james.kanze@gmail.com Conseils en informatique orientée objet/ Beratung in objektorientierter Datenverarbeitung 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34 |
|
![]() |
| Thread Tools | |
| |