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

ifstream question

P: n/a
Hi

I'm using ifstream (which I hardly ever use) to read an ascii text
file (containing numbers delimited by newlines) in a loop using
something like:

ifstream infile("filename")
int value;

infile >value;
while(!infile.eof() {
infile >value;
:

}

The problem is if the file is missing a terminating newline the final
number is missed. How can I make sure its read anyway when the newline
is missing?

Thanks for any help

B2003
Jan 29 '08 #1
Share this Question
Share on Google+
7 Replies


P: n/a
Alf P. Steinbach wrote:
* Boltar:
>>
I'm using ifstream (which I hardly ever use) to read an ascii text
file (containing numbers delimited by newlines) in a loop using
something like:

ifstream infile("filename")
int value;

infile >value;
while(!infile.eof() {
infile >value;
:

}

The problem is if the file is missing a terminating newline the final
number is missed. How can I make sure its read anyway when the newline
is missing?

Don't test for eof, test for good stream state, i.e. that last read was
successful.
The answer is in the FAQ:
http://www.parashift.com/c++-faq-lit....html#faq-15.5
Like

ifstream infile( "filename" );

for( ;; )
{
int value;

infile >value;
if( !infile.good() )
{
break;
}
// Do something with value.
}
if( !infile.eof() ) { /* oops. */ }
When I see this I start to believe, that break in loops is evil, as James
said. The example in the FAQ is not as ugly as this code.

--
Thomas
Jan 29 '08 #2

P: n/a

"Alf P. Steinbach" <al***@start.nowrote in message
news:13*************@corp.supernews.com...
* Boltar:
I'm using ifstream (which I hardly ever use) to read an ascii text
file (containing numbers delimited by newlines) in a loop using
something like:

ifstream infile("filename")
int value;

infile >value;
while(!infile.eof() {
infile >value;
:

}

The problem is if the file is missing a terminating newline the final
number is missed. How can I make sure its read anyway when the newline
is missing?

Don't test for eof, test for good stream state, i.e. that last read was
successful.

Like

ifstream infile( "filename" );

for( ;; )
{
int value;

infile >value;
if( !infile.good() )
{
break;
}
// Do something with value.
}
if( !infile.eof() ) { /* oops. */ }

Disclaimer: I really hate iostreams, so possibly that last check isn't
completely 100% cover-all-cases or guaranteed to detect failure.
Pardon, please, but:
Oh. Good. _Grief_!!
Alf, I just spent manydays trying to do exactly this above (get a number
from a file), but with a piece of code another kind poster provided ('cause
I was stumped) and I modified.
To wit:

/*usual headers and using n.s.*/
ifstream ifstr("tvrfile.tvr");
string txt("");
char *tmp;
getline( ifstr, txt, ',');
const int pNum(strtod(txt.c_str(),&tmp));
cout << pNum << "\n"; //stick into pNum later

.........only to find in yours here --that I didn't even _need_ strod() !
(I thought his was elegant when I first saw it; I'm such a newbie....)

I compiled your code and ran it.
The numbers _are_ numbers, without strtod() !
I will study this thread intensely.
Is this sort of thing common?

_Thanks_! (many additional exclams)
What a great resource and learning aid you people are!
--
Peace
JB
jb@tetrahedraverse.com
Web: http://tetrahedraverse.com

Jan 30 '08 #3

P: n/a

"Alf P. Steinbach" <al***@start.nowrote in message
news:13*************@corp.supernews.com...
* Boltar:
I'm using ifstream (which I hardly ever use) to read an ascii text
file (containing numbers delimited by newlines) in a loop using
something like:

ifstream infile("filename")
int value;

infile >value;
while(!infile.eof() {
infile >value;
:

}

The problem is if the file is missing a terminating newline the final
number is missed. How can I make sure its read anyway when the newline
is missing?

Don't test for eof, test for good stream state, i.e. that last read was
successful.

Like

ifstream infile( "filename" );

for( ;; )
{
int value;

infile >value;
if( !infile.good() )
{
break;
}
// Do something with value.
}
if( !infile.eof() ) { /* oops. */ }

Disclaimer: I really hate iostreams, so possibly that last check isn't
completely 100% cover-all-cases or guaranteed to detect failure.
May I please ask further?
I ran this, modified as follows:
(usual up-top-stuff)

int main() {
ifstream infile("file.ext");
for(;;)
{
double value;
char toss; /*remove the commas (delimiter) & newlines*/
if(!infile.good()) {break;}
cout<<value<<" ";
}
infile>>value; cout<<value; /*kludge does get the final number....*/
if (!infile.eof()) {/*oops*/} /*my kludge for oops...(?)*/
return 0;
}

.......and it, too, misses the last number in the file without the post-loop
single extra use of infile>>value....
I tried many things, including the FAQ version, and putting an extra \n onto
the end of the file being read. No go; same problem.
All lines of file, example: 2.3,45.90,23,-0.2334,0.9\n
I get a beautiful sequence of every number in the file, exactly what I
wanted, and they are all _numbers_ (hallelujah), but the last one's not
there.

Your code modified to my need does everything I want it to except catch the
last number in the file _without_ the ugly kludge....

Is there more to this _neat_ clean way of getting my numbers from the file,
that catches the last one but also allows use of the char non-number
tosser?

Thanks!
--
Peace
JB
jb@tetrahedraverse.com
Web: http://tetrahedraverse.com


Jan 30 '08 #4

P: n/a
On Jan 30, 11:47*am, "Alf P. Steinbach" <al...@start.nowrote:
* John Brawley:


"Alf P. Steinbach" <al...@start.nowrote in message
news:13*************@corp.supernews.com...
* Boltar:
I'm using ifstream (which I hardly ever use) to read an ascii text
file (containing numbers delimited by newlines) in a loop using
something like:
>ifstream infile("filename")
int value;
>infile >value;
while(!infile.eof() {
* * * *infile >value;
* * * *:
>}
>The problem is if the file is missing a terminating newline the final
number is missed. How can I make sure its read anyway when the newline
is missing?
Don't test for eof, test for good stream state, i.e. that last read was
successful.
Like
* *ifstream infile( "filename" );
* *for( ;; )
* *{
* * * *int value;
* * * *infile >value;
* * * *if( !infile.good() )
* * * *{
* * * * * *break;
* * * *}
* * * *// Do something with value.
* *}
* *if( !infile.eof() ) { /* oops. */ }
Disclaimer: I really hate iostreams, so possibly that last check isn't
completely 100% cover-all-cases or guaranteed to detect failure.
May I please ask further?
I ran this, modified as follows:
(usual up-top-stuff)
int main() {
ifstream infile("file.ext");
for(;;)
* * {
double value;
char toss; */*remove the commas (delimiter) & newlines*/
if(!infile.good()) {break;}
cout<<value<<" ";
* * }
infile>>value; cout<<value; */*kludge does get the final number....*/
if (!infile.eof()) {/*oops*/} */*my kludge for oops...(?)*/
return 0;
}
......and it, too, misses the last number in the file without the post-loop
single extra use of * infile>>value....
I tried many things, including the FAQ version, and putting an extra \n onto
the end of the file being read. *No go; same problem.
All lines of file, example: 2.3,45.90,23,-0.2334,0.9\n
I get a beautiful sequence of every number in the file, exactly what I
wanted, and they are all _numbers_ (hallelujah), but the last one's not
there.

Try 'infile.fail()' or just '!infile' instead of '!infile.good()'.

As I wrote, I hate 'em streams and so couldn't guarantee correctness.
IMO the problem is that EOF is simultaneously a character in the
stream and some sort of abstraction representing the end of the
stream.

IIRC is.good() holds even if next op is is.get() == EOF;

is.good() is meant to be true if characters are available, but IMO if
the next char is EOF then by definition no characters are available.

Further if EOF is a character and you are at eof(), then you should
IMO be able to is.putback(), but IIRC you can't.

I opted to wrap up text streams, so they all have the same semantic,
for files, console and strings. Any stream has a name, for files the
name of the file, for strings a name you supply and for console the
name of the console ( and a terminator you supply) Also every stream
keeps a record of line and column position, so you can output error
messages including name, and current position in a user friendly
format. Final part is a checkpoint stack, so you can create
checkpoints with useful messages, and they pop off the stack at the
end of their scope. Another stream type is a stream stack, where you
can push and pop streams (say for #include files, or macros. Its not
perfect as ideally you should be able to pushback through eof, but
because of the semantics of std::stteams this isnt really feasible.

However I do despair of the std::streams ...

I expect I will hear other opinions from experts about the issue :-)

regards
Andy Little

Jan 30 '08 #5

P: n/a
In article <2db713c3-6d93-4f93-8fed-ee7a71ad52e5
@y5g2000hsf.googlegroups.com>, an**@servocomm.freeserve.co.uk says...

[ ... ]
is.good() is meant to be true if characters are available, but IMO if
the next char is EOF then by definition no characters are available.
You're misinterpreting is.good(). It's meant to indicate the current
error state of the stream buffer. IOW, if the end of file has been
encountered, it should signal so -- but if it hasn't been encountered
yet, it should NOT signal so.

IMO, this is generally a good thing -- Pascal's I/O system worked as you
describe and it made writing correct loops considerably more difficult.
Further if EOF is a character and you are at eof(), then you should
IMO be able to is.putback(), but IIRC you can't.
Trivially true -- any statement of the form "if x then y' is true, but
meaningless if x if false. In this case, you start with the idea that
EOF is a character -- but since it's not, the rest of the statement
means nothing.
I opted to wrap up text streams, so they all have the same semantic,
for files, console and strings. Any stream has a name, for files the
name of the file, for strings a name you supply and for console the
name of the console ( and a terminator you supply) Also every stream
keeps a record of line and column position, so you can output error
messages including name, and current position in a user friendly
format. Final part is a checkpoint stack, so you can create
checkpoints with useful messages, and they pop off the stack at the
end of their scope. Another stream type is a stream stack, where you
can push and pop streams (say for #include files, or macros. Its not
perfect as ideally you should be able to pushback through eof, but
because of the semantics of std::stteams this isnt really feasible.
If you're wrapping the stream anyway, it's pretty trivial to add your
own capability to put things back, even when not supported by the stream
itself (just put whatever back into your own buffer, and have your input
routines check that buffer before reading from the stream).

Years ago, I wrote a wrapper for lexing C source code that wrapped C's
FILE * I/O. It allowed you to unget a more or less arbitrary amount of
data -- and unless memory serves me particularly badly today, it should
have still allowed you to unget (and read) data after the stream itself
had encountered EOF.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Jan 31 '08 #6

P: n/a
On Feb 1, 4:07 pm, Jerry Coffin <jcof...@taeus.comwrote:
In article <28432abe-730f-4a4c-8ef1-311adfef3131
@b2g2000hsg.googlegroups.com>, james.ka...@gmail.com says...
[ ... ]
I'd much rather write some sort of manipulator to
handle separators. Much more flexible, and much more accurate.
"Accurate" means it adheres more closely to some defined standard. In
this case, the only standard provided was his original description of
the file format, to which this adhered _perfectly_. As such, no higher
degree of accuracy is possible.
Accurate may not be the right word, but it didn't seem to me
that he wanted to have more than one comma handled as a single
separator. It looked more like he was dealing with a CSV
format.
Done correctly, for example, it wouldn't allow multiple
commas to be treated as a single separator.
This is a perfectly reasonable way of fulfilling that
requirement IF IT EXISTS. Claiming that it's more accurate is
simply a falsehood in this case. It's not really more flexible
either -- it simply fulfills a different set of requirements.
The general approach is more flexible, in that it allows for a
greater degree of variation in defining your separators (and
signaling an error if a separator isn't conform).
On one hand, if you want a series of separators to be
translated as a series of empty fields, it fulfills that
requirement quite nicely. OTOH, it makes it much more
difficult to meet a requirement that an arbitrary number
separators can be used to separate any two fields.
It's pretty trivial to add a loop on the comma.
Your solution would be extremely good if it was required --
but at least according to the OP, no such requirement exists.
That wasn't the way I interpreted what he said, but of course,
he didn't present an exact specification. In the end, it
probablyl depends on the wording in the specification: if the
specification says that commas are to be treated as white space,
then a new locale is a reasonable solution; if the specification
defines separators, then I think a manipulator which eats
separators is more appropriate. (I also think that a beginner
will reach the level of being able to write such manipulators
much sooner than being able to write a new locale. I know that
I have problems went I need to implement a new locale, and I'm
hardly a beginner.)

--
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
Feb 1 '08 #7

P: n/a
On Feb 1, 2:05 pm, "Alf P. Steinbach" <al...@start.nowrote:
* James Kanze:
[...]
I just refuse to go around remembering arcane details of iostreams.
They're that ugly. :-)
The naming conventions and the error handling are bad, I'll
grant you that. And of course, IF you use the "standard" idiom,
you don't have to remember them.

[...]
The most important reason to use it is because it is the
standard idiom.
[...]
(even if in this case, it's a bit longer.) But that's not the
issue here. I don't write it like that, however, because as I
said above---any time you see something other than what is in
the FAQ...
Let's not elevate the FAQ to infallible authority.
Both you and I have contributed to the FAQ (at least I think
you have, I know I have).
If it were only the FAQ, and other experts in iostream were
saying other things... But all of the people I know who are
really competent in iostream use the same idiom.
So saying our own statements and viewpoints etc. are godlike
authoritative just because they have ended up in the FAQ, it
would be a very circular argument :-), and besides, in
addition to much great advice, the FAQ also contains some
dubious statements and examples.
I know. (As it happened, this idiom predates the time I learned
C++, so I can't claim any responsibility for it.)
Most experienced programmers, on seeing such code,
would start by asking if I understood iostream, or if he knew
better, by asking what was special here that caused me to break
with the standard idiom.
Some idioms are good.
Some are not.
More precisely: the fact that something is an established idiom
is a positive point for it. Other, negative points, can
outweigh that. In this case, although I'd have done something
different if the idiom didn't exist, the bad points of the idiom
are small enough that they don't outweigh the advantage of using
the idiom.

--
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
Feb 1 '08 #8

This discussion thread is closed

Replies have been disabled for this discussion.