By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,194 Members | 802 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,194 IT Pros & Developers. It's quick & easy.

"inFile" object cannot read EOF

P: n/a
Hello. I'm studying the book "C++ Primer Plus" by Stephan Prata. In
chapter 6 he gives an exercise that reads from a file. The list is
thus:

4
Sam Stone
2000
Freida Flass
100500
Tammy Tubbs
5000
Rich Raptor
55000

So I create a istream object, inFile, and associate the file with
it. I know it reads the file because I've placed cout directives
after every read instruction. (since taken out). But I can't get the
program to read EOF.

After the following code there are conditions that test for
inFile.eof() and inFile.fail() but these get skipped over, to a
default "else" condition.

Can anyone see why EOF is not being recognized?
inFile >size;
donor *pd = new donor[size];
while(inFile.get() != '\n')
;

for(int i = 0; i < size; i++){
getline(inFile, pd[i].name); //a cout stmt here and
inFile >pd[i].cash; //here lets me know the data was
read
while(inFile.get() != '\n')
;
}

Jun 7 '07 #1
Share this Question
Share on Google+
15 Replies


P: n/a
waltbrad wrote:
Hello. I'm studying the book "C++ Primer Plus" by Stephan Prata. In
chapter 6 he gives an exercise that reads from a file. The list is
thus:

4
Sam Stone
2000
Freida Flass
100500
Tammy Tubbs
5000
Rich Raptor
55000

So I create a istream object, inFile, and associate the file with
it. I know it reads the file because I've placed cout directives
after every read instruction. (since taken out). But I can't get the
program to read EOF.
What do you mean by "to read EOF"? What's "EOF" in your statement?
After the following code there are conditions that test for
inFile.eof() and inFile.fail() but these get skipped over, to a
default "else" condition.
This is covered in the FAQ 5.8.
Can anyone see why EOF is not being recognized?
Every read operation ends with some kind of terminator. For example,
reading a number ('pd[i].cash') terminates at a symbol that cannot
be part of a number (like a newline). Most likely you never attempt
to read when the file cursor is _at_ the end of the file, to force the
'eof' bit to be set. Since you tell your program exactly how many
times to read, it doesn't fail to read, and that's why 'fail' bit is
not getting set either. Try removing the newline after the last
number in your file - make the third '0' in '55000' the _last_ symbol
in the file. You should see the difference.
>

inFile >size;
donor *pd = new donor[size];
while(inFile.get() != '\n')
;

for(int i = 0; i < size; i++){
getline(inFile, pd[i].name); //a cout stmt here and
inFile >pd[i].cash; //here lets me know the data was
read
while(inFile.get() != '\n')
;
}
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 7 '07 #2

P: n/a
On Jun 7, 2:58 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>
This is covered in the FAQ 5.8.
Hello again. Thanks for the response. Actually I was getting around to
your answer. But, you confirmed my suspicions, and I didn't know a way
to test them.

I waasn't aware that there was a faq for this newsgroup. Where can I
find it?

Thanks again.

Jun 7 '07 #3

P: n/a
waltbrad wrote:
>
I waasn't aware that there was a faq for this newsgroup. Where can I
find it?
http://www.parashift.com/c++-faq-lite/

DN
--
[there are no x's in my email]

I have the right to remain silent
(and should probably use it as much as possible)
Anything I type can and will be used against me
in a court of idiocy
I have the right to be wrong
(and probably am)
If I can not furnish my own wrongness
I'm sure someone will provide it for me.
Jun 7 '07 #4

P: n/a
waltbrad wrote:
On Jun 7, 2:58 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>>
This is covered in the FAQ 5.8.

Hello again. Thanks for the response. Actually I was getting around to
your answer. But, you confirmed my suspicions, and I didn't know a way
to test them.

I waasn't aware that there was a faq for this newsgroup. Where can I
find it?
http://www.parashift.com/c++-faq-lite/

Also, check out "Welcome to comp.lang.c++" message posted here every
now and then. If your server doesn't have it, search the archives.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 7 '07 #5

P: n/a
waltbrad wrote:
>
I waasn't aware that there was a faq for this newsgroup. Where can I
find it?
http://www.parashift.com/c++-faq-lite/

Mostly a great reference for a lot of concepts in C++, but has a section
devoted entirely to posting in this NG.

DN
--
[there are no x's in my email]

I have the right to remain silent
(and should probably use it as much as possible)
Anything I type can and will be used against me
in a court of idiocy
I have the right to be wrong
(and probably am)
If I can not furnish my own wrongness
I'm sure someone will provide it for me.
Jun 7 '07 #6

P: n/a
On Jun 7, 8:52 pm, waltbrad <waltb...@hotmail.comwrote:
Hello. I'm studying the book "C++ Primer Plus" by Stephan Prata. In
chapter 6 he gives an exercise that reads from a file. The list is
thus:
4
Sam Stone
2000
Freida Flass
100500
Tammy Tubbs
5000
Rich Raptor
55000
So I create a istream object, inFile, and associate the file with
it. I know it reads the file because I've placed cout directives
after every read instruction. (since taken out). But I can't get the
program to read EOF.
You can't "read" EOF, since by definition, a read fails if the
file is at EOF. You have to try to read something, and then
check whether it failed. After failure, you can check whether
it was due to EOF, or some other reason.
After the following code there are conditions that test for
inFile.eof() and inFile.fail() but these get skipped over, to a
default "else" condition.
I would help if you'd show them, however...
Can anyone see why EOF is not being recognized?
inFile >size;
donor *pd = new donor[size];
while(inFile.get() != '\n')
;
Why not simply: inFile.ignore( INT_MAX, '\n' ) ?

More generally, your file is line oriented, so it is probably
better to read it line by line, using an istringstream to
convert the numeric values (and verifying that the format is
correct). So the above would read:

std::string line ;
if ( ! std::getline( inFile, line ) ) {
// Error, file was empty...
}
std::istringstream sLine( line ) ;
if ( ! (sLine >size >std::ws) || sLine.get() != EOF ) {
// Error, first line didn't contain a number, or
// had extra junk at the end...
}

Given that your format includes lines with just a single number,
I'd probably wrap this into a separate function.

Finally, there's no reason in C++ to have to specify the count
at the start. Just use std::vector, and push_back until you
encounter end of file.
for(int i = 0; i < size; i++){
getline(inFile, pd[i].name); //a cout stmt here and
inFile >pd[i].cash; //here lets me know the data was
read
while(inFile.get() != '\n')
;
}
I'd write this loop something like:

std::vector< donor donors ;
std::string line1 ;
std::string line2 ;
while ( getline( inFile, line1 ) && getline( inFile, line2 ) ) {
double cash ;
std::istringstream sCash( line2 ) ;
sCash >cash ;
donors.push_back( donor( line1, cash ) ) ;
}

Except, of course, that it requires more error handling; the
above only works if the file has the correct format.

--
James Kanze (GABI Software) email:ja*********@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

Jun 8 '07 #7

P: n/a
On Jun 7, 10:51 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
waltbrad wrote:
On Jun 7, 2:58 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
This is covered in the FAQ 5.8.
Hello again. Thanks for the response. Actually I was getting around to
your answer. But, you confirmed my suspicions, and I didn't know a way
to test them.
I waasn't aware that there was a faq for this newsgroup. Where can I
find it?
http://www.parashift.com/c++-faq-lite/
Also, check out "Welcome to comp.lang.c++" message posted here every
now and then. If your server doesn't have it, search the archives.
Note that all of the FAQ's, to all groups, are available at
www.faqs.org. Back in the old days, this was pointed out to
people when they got their connection, but any sort of
responsability on the part of providers today seems to have gone
out the window.

--
James Kanze (GABI Software) email:ja*********@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

Jun 8 '07 #8

P: n/a

James Kanze wrote in message...
>** You can't "read" EOF **, since by definition, a read fails if the
file is at EOF.
So, my docs are wrong?
" Method: int istream::get ()
Read a single character ** (or EOF) ** from the input stream, returning it
(coerced to an unsigned char) as the result. "
You have to try to read something, and then
check whether it failed. After failure, you can check whether
it was due to EOF, or some other reason.
I once did this in some 'test' code:

// std::vector<unsigned charImage;
while( SomeInFile.peek() != EOF ){
// .... do stuff ....
// Image.push_back( SomeInFile.get() );
// if not reading single chars, need to check stream state.
}

Maybe it will help the OP to see the light. <G>

--
Bob R
POVrookie
Jun 8 '07 #9

P: n/a
BobR wrote:
James Kanze wrote in message...
>** You can't "read" EOF **, since by definition, a read fails if the
file is at EOF.

So, my docs are wrong?
" Method: int istream::get ()
Read a single character ** (or EOF) ** from the input stream,
returning it (coerced to an unsigned char) as the result. "
Whoever wrote that decided to shorten it a bit. What it should say
is "Read a single character from the input stream returning it, or
return a special value if the stream is in 'end-of-file' state".

In fact, istream::get() returns either the character it read or
'traits::eof()', according to the Standard. It doesn't "read" any
"EOF" from the stream.
> You have to try to read something, and then
check whether it failed. After failure, you can check whether
it was due to EOF, or some other reason.

I once did this in some 'test' code:

// std::vector<unsigned charImage;
while( SomeInFile.peek() != EOF ){
// .... do stuff ....
// Image.push_back( SomeInFile.get() );
// if not reading single chars, need to check stream state.
}

Maybe it will help the OP to see the light. <G>
Maybe...

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 8 '07 #10

P: n/a

Victor Bazarov wrote in message...
BobR wrote:
James Kanze wrote in message...
** You can't "read" EOF **, since by definition, a read fails if the
file is at EOF.
So, my docs are wrong?
" Method: int istream::get ()
Read a single character ** (or EOF) ** from the input stream,
returning it (coerced to an unsigned char) as the result. "

Whoever wrote that decided to shorten it a bit. What it should say
is "Read a single character from the input stream returning it, or
return a special value if the stream is in 'end-of-file' state".
Ok, I'll buy that. Thanks.
>
In fact, istream::get() returns either the character it read or
'traits::eof()', according to the Standard. It doesn't "read" any
"EOF" from the stream.
No "implementation defined" escape clause there? I'll check it out (for my
systems(win,GNU)) to satisfy my curiosity <G>.

--
Bob R
POVrookie
Jun 8 '07 #11

P: n/a
On Jun 8, 8:20 pm, "BobR" <removeBadB...@worldnet.att.netwrote:
James Kanze wrote in message...
** You can't "read" EOF **, since by definition, a read fails if the
file is at EOF.
So, my docs are wrong?
" Method: int istream::get ()
Read a single character ** (or EOF) ** from the input stream, returning it
(coerced to an unsigned char) as the result. "
Pourly worded. It "tries" to read a single character, returning
the character read, or EOF if it cannot read a character. EOF
is not a character, but a special out of band value. (That's
why get() returns int, and not char.)
You have to try to read something, and then
check whether it failed. After failure, you can check whether
it was due to EOF, or some other reason.
I once did this in some 'test' code:
// std::vector<unsigned charImage;
while( SomeInFile.peek() != EOF ){
// .... do stuff ....
// Image.push_back( SomeInFile.get() );
// if not reading single chars, need to check stream state.
}
Maybe it will help the OP to see the light. <G>
Yes. That's basically what I recommended at the filebuf level:
peek() simply returns rdbuf()->sgetc() (or EOF, if the rdbuf()
returns a null pointer).

--
James Kanze (Gabi Software) email: ja*********@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

Jun 8 '07 #12

P: n/a
On Jun 8, 10:42 pm, "BobR" <removeBadB...@worldnet.att.netwrote:
Victor Bazarov wrote in message...
BobR wrote:
James Kanze wrote in message...
>** You can't "read" EOF **, since by definition, a read fails if the
>file is at EOF.
So, my docs are wrong?
" Method: int istream::get ()
Read a single character ** (or EOF) ** from the input stream,
returning it (coerced to an unsigned char) as the result. "
Whoever wrote that decided to shorten it a bit. What it should say
is "Read a single character from the input stream returning it, or
return a special value if the stream is in 'end-of-file' state".
Ok, I'll buy that. Thanks.
The important point is that at this level, EOF is an out of band
value, and not a character. At this level, because...
In fact, istream::get() returns either the character it read or
'traits::eof()', according to the Standard. It doesn't "read" any
"EOF" from the stream.
No "implementation defined" escape clause there? I'll check it
out (for my systems(win,GNU)) to satisfy my curiosity <G>.
Most of what takes place in IO is more or less "implementation
defined". When it's not flattly unspecified In particular, how
an implementation represents line breaks and end of file is
unspecified, and may (and does under most systems) differ
between text files and binary. (For Unix, everything is pretty
much transparent, and there is no EOF character, either in text
or in binary files. I think that most Windows compilers,
however, still recognize the traditional CP/M end of file
character, 0x1A, in text files.)

Note that historically, a common error was writing the result of
istream::get() or istream::peek() (or earlier, getc() or
getchar()) to a char, and testing that for EOF (typically -1,
although any negative value is legal). This worked if (and only
if) plain char was signed, and the file never contained a 0xFF.
In ISO 8859-1, 0xFF is the 'ÿ' character (small Latin letter y
with diarese, if it doesn't show up right here). Not the most
common character, so the error often went unobserved.

--
James Kanze (Gabi Software) email: ja*********@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

Jun 8 '07 #13

P: n/a
In article <11**********************@q66g2000hsg.googlegroups .com>,
ja*********@gmail.com says...

[ ... ]
I'd write this loop something like:

std::vector< donor donors ;
std::string line1 ;
std::string line2 ;
while ( getline( inFile, line1 ) && getline( inFile, line2 ) ) {
double cash ;
std::istringstream sCash( line2 ) ;
sCash >cash ;
donors.push_back( donor( line1, cash ) ) ;
}
Personally, I think I'd do it a bit differently:

struct donor {
std::string name;
double cash;

// read a single donor's data:
friend std::istream &operator>>(std::istream &i, donor &d) {
std::getline(i, d.name);

std::string line2;
std::getline(line2);
std::istringstream temp(line2);
line2 >d.cash;
return i;
}
};

std::vector<donordonors;

std::copy(std::istream_iterator<donor>(infile),
std::istream_iterator<donor>(),
std::back_inserter(donors));

This does not require (or allow) the count at the beginning of the file
though...

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 10 '07 #14

P: n/a
On Jun 10, 2:23 am, Jerry Coffin <jcof...@taeus.comwrote:
In article <1181292953.700106.187...@q66g2000hsg.googlegroups .com>,
james.ka...@gmail.com says...
[ ... ]
I'd write this loop something like:
std::vector< donor donors ;
std::string line1 ;
std::string line2 ;
while ( getline( inFile, line1 ) && getline( inFile, line2 ) ) {
double cash ;
std::istringstream sCash( line2 ) ;
sCash >cash ;
donors.push_back( donor( line1, cash ) ) ;
}
Personally, I think I'd do it a bit differently:
I'd do it a lot differently in production code as well:-).
Starting with a lot more error handling.
struct donor {
std::string name;
double cash;
// read a single donor's data:
friend std::istream &operator>>(std::istream &i, donor &d) {
std::getline(i, d.name);

std::string line2;
std::getline(line2);
std::istringstream temp(line2);
line2 >d.cash;
return i;
}
};
Good point. Using a >operator is definitely the way to go.
std::vector<donordonors;
std::copy(std::istream_iterator<donor>(infile),
std::istream_iterator<donor>(),
std::back_inserter(donors));
This does not require (or allow) the count at the beginning of the file
though...
Neither did my version:-). In fact, as soon as you use
std::vector, you're freed from this constraint.

--
James Kanze (Gabi Software) email: ja*********@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

Jun 10 '07 #15

P: n/a
In article <11*********************@k79g2000hse.googlegroups. com>,
ja*********@gmail.com says...
On Jun 10, 2:23 am, Jerry Coffin <jcof...@taeus.comwrote:
[ ... ]
Personally, I think I'd do it a bit differently:

I'd do it a lot differently in production code as well:-).
Starting with a lot more error handling.
Well yes, I'd hope so -- but I was talking about basic structure, and
(at least in theory) the error handling shouldn't affect that a whole
lot. Of course, the ability to do exactly that is one of the biggest
arguments in favor of exception handling...

[ ... ]
This does not require (or allow) the count at the beginning of the file
though...

Neither did my version:-). In fact, as soon as you use
std::vector, you're freed from this constraint.
Right -- of course, you can avoid it without using std::vector, if you
want to badly enough. Chances are, however, that the firt several times
you try, you won't do the job as well as std::vector does...

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jun 11 '07 #16

This discussion thread is closed

Replies have been disabled for this discussion.