Streams and Files - II
The following topics are covered in this section:
To determine the present state of a stream, there are four bits (or flags) associated with every stream. They are:
Stream Status Flag |
Purpose |
badbit |
Set when a fatal error occurs. |
eofbit |
Set when the end of the stream is encountered (if stream relates to a file then it is set when end of file encountered) |
failbit |
Set when non-fatal error occurs (for example when invalid data is stored) |
goodbit |
It is set if there are no errors. |
Let’s see a very simple illustration of how you can make use of these bits. Let us create a class called ‘date’ which will be used to obtain the date from the user in the following pattern: DD-MM-YEAR
To achieve this we shall overload the >> operator.
The output if the input is typed correctly is:
Enter the date (separated by - ): 11-10-1981
The date is : 11-10-1981
The output if the input is typed incorrectly is as follows:
Enter the date (separated by - ): 11/10-1980
Error in the format of the date entered!
The date is : 11-0-0
The function used to set the ‘failbit’ is:
setstate( )
(Some compilers might not support this function). We have set the ‘failbit’ when the separator used by the user is something other than the ‘-’ character. As soon as the ‘failbit’ is set all further stream operations are ignored till the error is corrected (which is the reason why even ‘1980’ is not accepted by the program). The function:
istr.fail( )
is used to read the status of a stream. It will be discussed in the next section.
Reading the status of a stream:
We have learnt about the stream status flags and we have even discussed as to how the flags could be set. To identify which status bit has been set we can make use of corresponding member functions.
Function |
Stream Status Flag checked |
int bad ( ) |
badbit |
int eof ( ) |
eofbit |
int fail ( ) |
failbit |
int good ( ) |
goodbit |
‘cin’ is a stream and even its ‘failbit’ can get set as shown in the program below:
The output for a value that exceeds the short integer range will be:
Enter a short integer : 56432
Error in input
The number stored is :32767
The fail ( ) function will return a non-zero value if the number entered by the user exceeds the limit of a short integer. If this is the case then the ‘if’ condition is satisfied and the loop is executed.
Usually we will not be using the stream status flags as shown in the above case. The same concept will be applied for files (because files are also accessed via streams and all the points discussed here are relevant for files).
Remember: Once any of the error bits are set, they will continue to remain set till they are cleared.
For example:
The output if a proper value is entered is:
Enter a short integer : 20
Enter an integer:24
The failbit value is : 0
The output for a higher value is:
Enter a short integer : 45345
Error in input
The number stored is :32767
Enter an integer:
The failbit value is : 2
In the second case, the ‘failbit’ for the stream ‘cin’ is set to 2 (because a very high number was entered initially). This bit hasn’t been reset and thus ‘cin’ cannot be used to obtain the value for the second integer (the program will not allow the user to enter a value because the ‘cin’ stream has an error).
The modified program will be:
The output is:
Enter a short integer : 1232345
Error in input
The number stored is :32767
All error flags cleared.
Enter an integer:2
The failbit value is : 0
If no argument is specified for clear ( ) function then all the error bits are cleared. After the clear ( ) fucntion is executed, good ( ) function will return a TRUE value (because there are no errors now). Suppose you want to set the ‘failbit’ and reset the other bits, you can type:
.clear(ios::failbit);stream-name
This will reset all the error bits and will set the ‘failbit’. Similarly you can set other bits also.
So far we have dealt with standard I/O. Next we shall deal with file I/O and to access any device you have to make use of another header file: ‘fstream.h’. This header file has a number of classes already defined. To access a file you have to have a stream. We have already come across the classes istream, ostream and iostream. From these classes, 3 more classes are derived (they are ofstream, ifstream, and fstream) and these classes are specifically useful for streams used in ‘file’ operations. The hierarchy of classes will be as shown in the figure.
As can be seen, the ‘ifstream’, ‘ofstream’ and ‘fstream’ classes are derived from the ‘istream’, ‘ostream’ and ‘iostream’ classes. These are file streams that are derived from the general I/O streams that we have seen earlier.
ifstream in;
// file stream named ‘in’ created for handling input
ofstream out; // file stream
named ‘out’ created for handling output
fstream both; // file stream
named ‘both’- can handle both input and output
Once you've created a stream, you can use the open ( ) function to associate it to a ‘file’. To associate the stream to a disk file, we should specify the name of the disk file. The open ( ) function is a member available in all the three classes. It can be used as follows:
out.open("text.txt") ; // Opens a file called text.txt for output.
Remember: When you say that a file is opened for output, it actually means that now you can write data to the file. When a file is opened for input (i.e. using ifstream), the data in the file can be displayed on the screen.
What if there already is a file called text.txt. When using the output stream (ofstream), the stream will create a new file text.txt. Whatever content was there in the original text.txt gets deleted and you can write new data to text.txt.
The 3 classes (ofstream, ifstream, fstream) have a constructor function that makes it easier to open a file. Example:
ofstream out("text.txt");
This creates an object out for output and opens the file text.txt in one single statement. Here we don’t make use of the open ( ) function.
Anything that you open has to be closed. The member function for closing is close ( ). Since you do all I/O through the stream, you have to close the stream as follows:
.close( );stream-name
Actually you can link this back to the object and classes concept. ‘stream-name’ is an object and close is a member function of the ofstream class. Hence by saying
.close( );stream-name
you're actually invoking the member function close( ). A stream is associated to a device when using the open function. When the close ( ) function is used, the stream is disassociated from the device.
Can Errors occur while opening a file?
When you open a file using ofstream (which means for output), you can write data to the file. You could say it's an input to the file. Hence open for output means actually for input.
When a file is opened for reading, you will make use of the ifstream as follows:
ifstream instr("test.txt"); // The file test.txt is opened for reading
Beware: Many beginners confuse between the use of ‘ifstream’ and ‘ofstream’ objects. Be clear as to what you want to use.
When you want to read a file, it implies that the file is already present in your directory. What will happen if we attempt to open a file that is not present?
This will cause an error and you should provide the necessary coding to deal with this situation. When you open a file for writing data, the stream will create the file even if it doesn't exist. But if you attempt to open a file for reading data and if it isn't present in the computer, this will cause an error. You should always check whether an error has resulted while using the open operation as follows (‘instr’ is an object of type ifstream):
if ( ! instr )
{
cout<< "The file cannot be opened";
}
if ( ! instr ) stands for : ‘if not instr’ (that means ‘if instr not open’) then do what is said in the body of the if statement.
Go back to the Contents Page 2
Copyright © 2004 Sethu Subramanian All rights reserved.