Reputation: 786
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?
Upvotes: 4
Views: 6809
Reputation: 2554
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.
Upvotes: 6
Reputation: 70939
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.
Upvotes: 0
Reputation: 74058
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.
Upvotes: 0