File I/O Using the ifstream and ofstream Classes

  1. We start by introducing the idea about classes.
    • A class is a data type whose variables are objects.
    • An object is a variable that has functions associated with it, as well as the ability to hold data values.
    • These associated functions are attached to the object and are referred to as the object's member functions.

  2. C++ has the following two classes of objects to handle file I/O.
    • The class ifstream has objects that are input file streams.
    • The class ofstream has objects that are output file streams.

  3. Definitions of these file streams are located in the header file fstream and so the following directive must be included:

    #include <fstream>

  4. Before a file stream can be used for I/O, it must be declared just as you would declare any other variables. The type for input file stream variables is ifstream. The type for output file stream variables is ofstream.

  5. For example you declare in_stream to be an input file stream and out_stream to be an output file stream as follows:

    ifstream in_stream;
    ofstream out_stream;

  6. Let us consider the value of a stream.
    • Just like an ordinary variable, which must be assigned a value before it can be used in an expression, an object variable must also be given a value before it can be used.
    • Stream variables (objects), such as in_stream and out_streams declared above, must each be connected to a file. You can think of the file that a stream is connected to as the value of the stream.
    • Connecting a stream to a file is called opening the file.
    • However unlike an ordinary variable which can be assigned a value using the assignment operator =, objects such as a stream get values through the use of their member functions.
    • The member function named open allows input and output file streams to be connected to a file.
    • The name of the file must be enclosed in double quotes and must be given as argument of the member function open.
    • For example the following code can be used to connect the input file stream in_stream to the file called infile.dat:

      in_stream.open("infile.dat");

    • Similarly the following code can be used to connect the output file stream out_stream to the file called outfile.dat:

      out_stream.open("outfile.dat");

  7. Once they have been connected to the proper files, these input file streams and output file steams can be used in the same way that the standard input stream cin and output stream cout are used.

  8. For example, if you have an input file stream named in_stream that is connected to a file called infile.dat, then an integer variable named one_number can be filled with a number from that file using the following code:

    #include <fstream>
    ...
    int one_number;
    ifstream in_stream;
    ofstream out_stream;

    in_stream.open("infile.dat");
    out_stream.open("outfile.dat");

    in_stream >> one_number;     // just like how cin is used to read
                 // a number from the keyboard
    cout << "The number read is: " << one_number << endl;

    Before you run the program, you must have created an external (outside the program) file called infile.dat and must have written numbers in that file using a text editor. If the first line in the external file infile.dat contains the following:

    64 -7 1064 ...

    the resulting screen output is:

    The number read is: 64

    Subsequent use of

    in_stream >> another_number;    
    cout << "The next number is: " << another_number << endl;

    will read the next number in the file infile.dat and so the screen output is:

    The next number is: -7

    Reading a file this way is sequential. You cannot normally go back and read anything in the file a second time, nor can you skip some data and read ahead. Of course there are ways to get around that.

    Now the values of the above two numbers can be written out to the file named outfile.dat as follows:

    out_stream << "Another number = " << another_number
        << ", One number = " << one_number << endl;

    After the program is run, if you open the file outfile.dat with a text editor, then you will find the following line there:

    Another number = -7, One number = 64

  9. When used with an output file stream of type ofstream, the member function open will create a file whose name is given as the argument of the open function, if that file does not exist. However, if a file with that name does already exist, the function will empty the contents of the file. Therefore the file is always empty after a call using the open member function of a stream in ofstream.

  10. Every file that is opened should be closed when your program is finished getting input from the file, or sending output to the file.

  11. Closing a file disconnects the stream from the file. We can connect a different file to that stream if we want to. This is like changing the value of an ordinary variable.

  12. A file is closed with a call to the member function close of the input or output file stream.

  13. For example, the file infile.dat is closed using:

    in_stream.close( );

  14. The member function close takes no arguments.

  15. If your program ends normally but without closing a file, the system will automatically closes the file for you. However it is always good to close a file when you are done with it. If your program ends abnormally due to an error, and if the file is not closed, then it may be left in a corrupted state. A corrupted file occupies space but no program can work with it.

  16. The only way to access a file is to declare an input or output file stream, connect the file to the file stream using the file stream's open member function with the name of the file as argument, and refer to the name of the file stream every time you want to access that file.

    The only place where the name of the external file appears is in the open function. (As we will see below, file stream objects can also be initialized.) You cannot directly refer to the external file name in your program.

  17. The syntax for calling member function of an object is:

    Calling_Object.Member_Function_Name(Argument_List);

    The name of the object is put first, follows by a dot. The name of the member function of the object is put after the dot, and is followed by the argument list of the member function enclosed in parentheses.

  18. For example:

    in_stream.open("infile.dat");
    out_stream.open("outfile.dat");
    out_stream.precision(2);
    out_stream.close( );

  19. The dot is referred to as the dot operator.

  20. The parentheses must be included even if the member function has no arguments.

  21. One has to be much more careful when working with external files. A call using the member function open to open a file for input or output can fail for a number of reasons. For example:

    • There may be no file with the name specified in the argument of the open member function. The file name may be wrong, or the file is located in a different directory.
    • There may be insufficient disk space left on the hard drive to open such a file.
    • If you are trying to read from a file stored on a floppy diskette, but you may have forgotten to put the diskette in the floppy disk drive.
    • The diskette may be write-protected so that open cannot create such a file.

  22. It is therefore important to follow a call to open with a test to see if the call was successful. Take appropriate actions if the call was not successful.

  23. This test can be performed using the member function fail for each of the classes ifstream and ofstream. This function takes no arguments and returns a bool value of true if the call to open fails, otherwise it returns false

  24. For example, in_stream.fail( ) is a boolean expression that can be used to control a loop or an if-else statement.

  25. If the call fails, appropriate action must be taken. One possibility is to use the exit statement: exit(1) to end the program immediately. The argument of the exit function is returned to the operating system. A 1 signifies an abnormal exit and a 0 for normal exit. The header file where the exit function is defined is cstdlib.

  26. An example is shown below.

    //Read three numbers from the file infile.txt, sum them
    //and write the sum to the file outfile.dat.
    #include <fstream>
    #include <iostream>
    #include <cstdlib>
    using namespace std;

    int main( )
    {
          int first, second, third;      // to store 3 integers to be read from file
          ifstream in_stream;      // declare an input file stream object
          ofstream out_stream;      // declares an output file stream object

          in_stream.open("infile.txt");      // open (connect) input file stream
                                    // object to external file infile.txt
          if (in_stream.fail())      // check for connection failure
          //if (!in_stream)      // This also works!
               {
                    cout << "Input file opening failed.\n";
                     exit(1);      // exit program immediately
               }

          out_stream.open("outfile.dat");      // open (connect) output file stream
                                     // to external file outfile.dat
          if (out_stream.fail())
               {
                     cout << "Output file opening failed.\n";
                     exit(1);           // there is actually a problem here, can you spot it?
                        // we'll present another version of this program later
                        // which will correct the problem here
               }

          // Read 3 integers from the input file
          // Notice the usage is exactly like cin.
          in_stream >> first >> second >> third;

          // Output the sum to the output file
          // Notice the usage is exactly like cout.
          out_stream << "The sum of the first 3\n"
                      << "numbers in infile.txt\n"
                      << "is " << (first + second + third)
                      << endl;

          // Make sure to close all opened files before program finishes:
          in_stream.close( );
          out_stream.close( );
          // Under normal circumstance, these files will be closed after the program is done,
          // since the stream variables (objects) are out-of-scope.

          return 0;
    }

  27. A stream object can also be given a value when it is declared (i.e. initialized). For example we can write:

    ifstream in_stream("infile.txt");

    to declare the ifstream object in_stream and attach it to the external file infile.txt.

    This single statement is equivalent to the following two statements:

    ifstream in_stream;
    in_stream.open("infile.txt");