0

trying to read/print contents of a file, where the last line does not end with '\n'. Program simply misses that data

while ( !readFile.eof() ) {
    string s;
    getline( readFile, s );
    if ( readFile.eof() ) break;
  //operate on data...
    cout << s << endl;
}

1 Answers1

4

Please refer to Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?

You need to move the std::getline() call into the while statement directly:

string s;
while ( getline( readFile, s ) ) {
  //operate on data...
  cout << s << endl;
}

The loop will run until EOF is reached and there is no more data to read. Whether the last line is delimited with a line break or not is irrelevant, as std::getline() will do the right thing and return the last line's data even if it is not delimited.

So, std::getline() actually does return the last line even if it is not delimited, but you are simply ignoring it, because this logic:

getline( readFile, s );
if ( readFile.eof() ) break;
//operate on data...

Breaks your loop prematurely if the last line is not delimited, because std::getline() will set eofbit on readFile when it encounters EOF while reading, however s will actually contain the last line's data, which you then ignore.

By moving the std::getline() directly into the while statement, it will then rely on the stream's bool conversion operator, which will return true if eofbit is set and none of the error flags are set (failbit or badbit), allowing the loop to process a non-delimited line. When the next loop iteration then tries to read past EOF, std::getline() will set failbit on the stream, causing the bool operator to return false, breaking the loop.

image

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • this method only works if the last line of data includes a '\n' – Rocco Ruscitti Dec 12 '19 at 02:04
  • @RoccoRuscitti that is not true. If the last line does not have a line break, `std::getline()` will simply read until EOF, set `eofbit` on the stream, and return whatever it read. The stream's `bool` operator returns true when only `eofbit` is set, so the loop will not break on EOF itself. Only when `std::getline()` tries to read past EOF will `failbit` then be set on the stream and the `bool` operator will return false, breaking the loop. – Remy Lebeau Dec 12 '19 at 02:07
  • I would expect that to be true, but the program that I wrote today did not yield that result unless I used a ternary conditional – Rocco Ruscitti Dec 12 '19 at 02:11
  • @RoccoRuscitti See my comment to your answer about the ternary operator. It doesn't do what you think it does – Remy Lebeau Dec 12 '19 at 02:11
  • I know what happened: I forgot to recompile my .cpp file with the print function when I used your solution before I attempted it again using the ternary operator, so it didn't appear to work, but as you say, the ternary solution is the same solution with a redundancy – Rocco Ruscitti Dec 12 '19 at 02:23
  • This is horribly counter-intuitive. In order to read up to the end of file, one needs a (implicit) function that returns `true` while `eof` is set. And to top it all of, none of the function names match the equivalent flag names. The designers of this library must have been on drugs or something. Yikes. Sorry for the rant. – Emanuel P Jul 29 '22 at 10:20