3

I have a n X 2 matrix stored in a text file as it is. I try to read it in C++

nb_try=0;
fin>>c_tmp>>gamma_tmp;
while (!fin.eof( ))      //if not at end of file, continue reading numbers
{
  // store
  cs_bit.push_back(c_tmp);
  gammas_bit.push_back(gamma_tmp);
  nb_try++;

  // read
  fin>>c_tmp;
  assert(!fin.fail( )); // fail at the nb_try=n   
  if(fin.eof( ))break;
  fin>>gamma_tmp; // get first number from the file (priming the input statement)
  assert(!fin.fail( ));    

}

The first assert failes, i.e. fin.fail( ) is true, when nb_try==n, which happens when it tries to read the first number which does not exist. But how come fin.eof( ) is not true after reading the last number? Does it mean it becomes true only when reading the first number that does ot exist? Also is it true that fin.fail( ) and fin.eof( ) are becoming true at the same time?

Thanks and regards!

Tim
  • 1
  • 141
  • 372
  • 590

3 Answers3

17

This is the wrong way to read a file:

while (!fin.eof( ))
{
      // readLine;
      // Do Stuff
}

The standard pattern is:

while(getlineOrValues)
{
    // Do Stuff
}

So looking at your code quickly I think it would be asier to write it as:

while(fin>>c_tmp>>gamma_tmp)
{
    // loop only eneterd if both c_tmp AND gamma_tmp
    // can be retrieved from the file.

    cs_bit.push_back(c_tmp);
    gammas_bit.push_back(gamma_tmp);
    nb_try++;   
} 

The problem is that EOF is only true AFTER you try and read past it. Having no character left in the file to read is not the same as EOF being true. So you read the last line and get values and there is nothing left to read, but EOF is still false so the code re-enter the loop. When it tries and read the c_tmp then EOF gets triggered and your asserts go pear shaped.

The solution is to put the read as the while condition. The result of doing the read is the stream. But when a stream is used in a boolean context (such as a while condition) it is converted into a type that can be used as like a bool (Technically it is a void* but thats not important).

Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Thanks! when exactly fin.eof() becomes true? After reading the last number in the file or after trying to read the first number which does not exist? Same question for fin.fail()? – Tim Sep 29 '09 at 19:16
  • 2
    EOF is true when you try and read __past__ the EOF. Reading upto the end of file does not change the state. So EOF becomes true when you read the first value that does not exist past the end of file. – Martin York Sep 29 '09 at 19:18
  • Thanks again! this clarify EOF. For ifstream::fail(), does it become true when first reading past the end of the file just as eof() does? In my example, it seems to be true. But I learned from http://www.cplusplus.com/reference/iostream/ios/fail/ that "The function returns true if either the failbit or the badbit is set. At least one of these flags is set when some error other than reaching the End-Of-File occurs during an input operation". Does it say fail() doesn't become true only because EOF occurs? – Tim Sep 29 '09 at 20:54
  • ifstream::fail() doesn't imply eof, see here for an explanation of the state flags: http://www.cplusplus.com/reference/iostream/ios_base/iostate/ – Georg Fritzsche Sep 29 '09 at 21:56
  • The fail bit is set if the last operation failed. In this case the fail and eof will become true at the same time. But this does not imply that fail and eof are the same thing. Note the fail will be set if you try and read a non numeric string into an int variable with operator >> etc. At this point the fail bit is true but eof is still false. – Martin York Sep 29 '09 at 22:06
  • After [doing some research](http://stackoverflow.com/q/14591203/150634), I think this popular explanation for why you shouldn't do `!fin.eof()` is actually incorrect. The `eof` bit really is set when an extraction stops at the end of the file, without you doing another read. The reason there is an extra extraction when reading from text files is because they're often ended with an extra `\n` character. The last line will be read, stopping at this `\n` character and *not* setting the `eof` bit and then the next extraction will fail because there is nothing to extract after this final `\n`. – Joseph Mansfield Jan 30 '13 at 12:44
  • Another reason to not do `!fin.eof()`, other than this extra invalid read from text files, is that the loop will execute in other situations where you have an invalid line. A serious case of this is when the file didn't even open correctly. – Joseph Mansfield Jan 30 '13 at 12:48
  • @sftrabbit: Your first comment is wrong The EOF flag is not set until you read past the end of file. The last successful read will read upto but not past the EOF. Try it with a file with no `\n` on the last line. Your second comment is true. But as a result people will try `while(!fin.bad())` which then runs into the same problem as above. – Martin York Jan 30 '13 at 19:31
  • @LokiAstari Take a look at the question I linked to. When I try it with no `\n` on the last line I get the EOF bit set. The answer explains that while extracting, if it reaches the end of the file the EOF bit is set. This isn't a failure though. It is only on the next read that the fail bit will be set because the EOF bit was set previously. – Joseph Mansfield Jan 30 '13 at 19:37
  • I just tested it with a file too. It really does behave the same way as with the stream. If you absolutely definitely certainly make sure there's no `\n` at the end, a single extraction will cause the EOF bit to be set. Most text editors hide the last `\n` like a dirty secret so I had to do `:set noeol` and `:set binary` in vim before I saved the file to stop it from adding that new line. – Joseph Mansfield Jan 30 '13 at 22:08
  • @sftrabbit: Opps. OK. I see the same behavior now. But my original statement holds. The EOF flag is not set until you read past the end of file. You can read the whole file (but if you don't read passed the end EOF is not set). The difference here is the formatted input `operator>>` is actually reading passed the end of file to find the end of the input. For both the string example and my number example behave as described above. – Martin York Jan 30 '13 at 22:50
5

IIRC, the eofbit doesn't get set until you actually try to read past the end of the file. That is, once you reach the end of the file, you have to read one more time before that flag will be set.

bambams
  • 745
  • 1
  • 8
  • 18
0

If the text file contains this sequence, without quotes, "12345 67890", then #3 will return false, but #4 will return true because there is no whitespace after the last number:

int i;
bool b;

fin >> i;

b = fin.fail();  // 1
b = fin.eof();   // 2

fin >> i;

b = fin.fail();  // 3
b = fin.eof();   // 4

fin >> i;

b = fin.fail();  // 5
b = fin.eof();   // 6

However, if the sequence is "12345 6789 " (note the space after the last number), then #3 and #4 will both return false, but #5 and #6 will return true.

You should check for both, eof() and fail() and if both are true, you have no more data. If fail() is true, but eof() is false, there's a problem with the file.

Andre
  • 94
  • 3