Don’t assume a file stream has been opened successfully.
Incorrect file name:
inFile.open("names.txl");
Incorrect file opening mode:
ifstream inFile;
inFile.open("names.txt", ios::trunc);
Not enough room on the hard drive.
Hardware failure.
Always check the status of a stream after open.
So the file seemed to open okay but being pessimistic, what goes wrong next.
The program may not have data to read as it hits the end of file.
The data may be invalid: ... an alphabetic character instead of a digit character; a control character instead of an alphabetic one; etc.
The data may not be physically accessed from the disk due to its damage or network failure.
Comprehensive error checking is needed, and appropriate error recovery. C++ provides three status flags and four functions to detect possible errors.
The flag eof indicates that the end of file is reached.
if (input_file_data.eof()) {
Error recovery action
}
The flag fail indicates a failure due to invalid data.
if (input_file_data.fail()) {
Error recovery action
}
The flag bad indicates a hardware problem.
if (input_file_data.bad()) {
Error recovery action
}
The function good() returns true if no error of any kind has been detected.
Note that files are viewed here as sequences of bytes with an end-of-file character at the end.
1 2 3
<Assuming appropriate headers>
while (!input_file_data.eof()) {
input_file_data >> number;
cout << number << " ";
}
1 2 3 3
eof() doesn’t test for the end-of-file. It simply returns a value of the corresponding indicator. The indicator is changed by >> attempts.
Once the stream is in the error state, it will stay that way until you take specific action:
All subsequent operations will do nothing, or loop forever no matter what they are or what is in the input.
You have to clear the stream by calling clear() to recover the stream from the fail state.
inFile >> newNumber;
if (inFile.fail()) { inFile.clear(); inFile.ignore(100, ‘\n’);}
clear() - Recovers the file stream from the error state. However, further reading of data may be useless as the wrong characters are still in the stream buffer.
ignore(100, '\n') - Discards 100 characters (or until the end-of-line indicator) from the stream buffer.
int readData(ifstream& inFile, InfoType& student, string myId)
{
string nameFirst;
string nameLast;
string Id;
do inFile >> nameFirst >> nameLast >> Id;
while( inFile.good() && Id != myId );
if(inFile.fail()) // invalid character
return -1;
if(inFile.bad()) // hardware failure
return -2;
if(inFile.eof() && Id=="") // myId not found
return -3;
student.firstName = nameFirst;
student.lastName = nameLast;
student.Id = Id;
return 0;
}
How do we read all characters from the input stream; including blanks, tabs, and new-lines?
This could be an input file stream or something else, like standard in.
The extraction operator doesn’t read white space or characters.
You can use get functions to read a character:
ifstream inFile;
char nextChar;
nextChar = inFile.get();
You can use getline to read a line of characters from a text file.
char lineBuffer[bufSize];
infile.getline( lineBuffer, bufSize );
float price;
char productName[20] ;
char fileName[] = "test.txt";
ifstream inData;
Motor Oil
inData.open( fileName );
inData >> price;
inData.getline(productName, 20);
cout << price << endl;
cout << productName << endl;
The newline character is still in the stream buffer, and that is interpreted as an empty string. So, we need to clear the buffer:
inData >> price;
inData.ignore( 20, ‘\n’ );
inData.getline(productName, 20);
34.99
Motor Oil
It’s often unreasonable to forecast the input length. So we can use this form:
getline(cin, input);
This has a default delimiter or endpoint of \n, that’s a new line.
But you can change this:
getline(cin, input, ’t’);
Be careful with this, you can capture a lot more than you expect.