4

I want to read from two files until I reach the end of one of them. If something goes wrong, the fstream should throw an exception.

The problem is, that bad or fail bit is also set when eof bit is set.

ifstream input1;
input1.exceptions(ios_base::failbit | ios_base::badbit);
input1.open("input1", ios_base::binary | ios_base::in);

ifstream input2;
input2.exceptions(ios_base::failbit | ios_base::badbit);
input2.open("input2", ios_base::binary | ios_base::in);

ofstream output;
output.exceptions(ios_base::failbit | ios_base:: badbit);
output.open("output", ios_base::binary | ios_base::out | ios_base::trunc);

char in1, in2, out;

while(!input1.eof() && !input2.eof()) {
    input1.read((char*) &in1, 1);
    input2.read((char*) &in2, 1);
    out = in1^in2;
    output.write((const char*) &out, 1);
}

input1.close();
input2.close();
output.close();

This leads to

$ ./test
terminate called after throwing an instance of 'std::ios_base::failure'
  what():  basic_ios::clear

How to do it right?

firefexx
  • 666
  • 6
  • 16

3 Answers3

6

The basic problem in your code is a FAQ. You should never use eof() as a test condition of a read loop because in C/C++ (unlike some other languages) eof() is not set to true until you have read past the end of file, and therefore the body of the loop will be entered once too many times.

The idiomatically correct procedure is to have the read operation itself in the loop condition, so that the exit occurs at the correct point:

  while ( input1.get(in1) && input2.get(in2) ) { /* etc */ }
  // here, after the loop, you can test eof(), fail(), etc 
  // if you're really interested in why the loop ended.

This loop will end naturally with the exhaustion of the smaller input file, which is exactly what you want.

arayq2
  • 2,502
  • 17
  • 21
  • 1
    Thanks, but this code still throws the exception when end of file is reached. – firefexx Jan 25 '13 at 15:32
  • 1
    That's because you _asked_ for exceptions. The point is that you do _not_ need any exceptions at all to detect end of input. – arayq2 Jan 25 '13 at 20:09
  • 1
    Besides, you really don't want to use exceptions with this API. See, e.g. [this](http://stackoverflow.com/questions/3180268/why-are-c-stl-iostreams-not-exception-friendly) and the update above to the code fragment – arayq2 Jan 25 '13 at 23:02
0

Simply remove the .eof() if(fstream) checks all bits (eof bad and fail).

So re write the while as:

 while(input1 && input2)

And then maybe verify that eof() returns true for at last one of the streams.

Hope this helps.

quamrana
  • 37,849
  • 12
  • 53
  • 71
Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
0

Don't throw an exception at all and use input1.read or istream::get in your while condition

while (input1.get(in1) && input2.get(in2)) {
...
}

If you read the characters in your loop body, you will have an additional character in your output, with no corresponding input characters. Maybe this is the reason, why you used std::ios::exeptions in the first place.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198