You have just read (and printed) the last "word" from the file. There is still whitespace in the file after the word. Stream is not at EOF yet. No read has failed yet. You can do one more iteration.
Why the Windows version does not seem to do that additional iteration? That is a mystery.
1 2 3 4 5
string s;
while ( fs >> s ) // true, if read is successful
{
cout << "s is " << s << endl;
}
With the line: while (!fs.eof() && fs.good()) does not work the way that you think it does.
"fs.good()" is always true until the file stream is closed.
Checking for "eof" before you read from the file does not catch when the end of file until it is to late and you process something that was not be read.
My experience has been in the 2011 standards when the stream failed the variables would retain their last value. When I started using the 2014 standards I noticed that when the stream failed numeric variables would be set ot (0)zero and strings to empty.
In your Linux example you show 3 lines for the input file and 5 lines of output. Did you miss a line on the input file?
It would be better to write the while loop as: while (fs >> s). This way when the read fails, say when "eof" is set, the while condition fails and the loop is bypasses.
This if fairly normal for reading a file of unknown length.
@uplife1980 it is extremely rare that you need to use .eof(). Also .good() or .bad()/.fail() are usually only used after a stream extraction to check that the extraction has worked or not (especially if a number (int or double) is read).
In other situations, the stream state is usually checked as part of the stream extraction - often as the condition in a while or for loop. Eg
1 2 3
while (fs >> s) {
// good extraction - process s
}
The thing to remember about eof() is that it isn't true until you try to read past the end of the file. After you read the last character of the file, eof() is still false. When try to read another character, it becomes true.
Another thing to keep in mind, which they don't seem to teach in schools, is that it's okay to put the loop test in the middle of the loop. That's often the most logical place to put it. So modifying HandyAndy's method (although seeplus's is preferable):
1 2 3 4 5
whiletrue() {
fs >> s;
if (fs.eof || !fs.good()) break;
cout << "s is " << s << '\n';
}
If fs >> s fails then the value of s doesn't change and although the stream extrazction didn't work, the cout << statement is still executed and the previous value of s. Hence display the last line twice.
The program would be coded as:
1 2 3 4 5 6 7 8 9 10 11 12 13
#include <fstream>
#include <iostream>
int main()
{
std::ifstream fs("config.txt");
if (!fs)
return (std::cout << "Cannot open input file\n"), 1;
for (std::string s; fs >> s; )
std::cout << "s is " << s << '\n';
}
Thank you keskiverto, HandyAndy, dhayden and seeplus , I finally figure out my mistake. Besides, I guess the different results may be a result of different compilers' implement?