Activity 5-1 - Reading from/Writing to a file
                       Using Streams for Program I/O



So far, you have read the input to your programs from the keyboard and have written (displayed) your results on the screen. Input data read from the keyboard and output data written to the screen are temporary and will be lost when the program ends.  In this lab, you will learn to read from/write to a file which will remain on the hard disk until you manually remove them.  The reading from/writing to a file in a program is usually referred to as file I/O (Input/Output).  You will use constructs call streams to read/write your data to or from a file.  Streams are the first examples of objects introduced in this course.  An object is a special kind of variable.  C++ is an Object Oriented Programming (OOP) language, i.e., it has the ability to handle objects.

In order to read from/write to a file, we need to take some precise steps.  Missing any of these steps, will result in failure to correctly read from/write to a file.  Following are the steps that you need to go through to successfully perform the file I/O.

"Remember you cannot use a stream of type input to write to a file and vice versa"

Step (1): Include the required directives
#include<fstream>   // This enables you to do file I/O
#include<iosream>  // For cin and cout
#include<cstdlib>   // To use exit(1) that terminates the program
using namespace std;

Step (2): Create the input/output streams
If fixed file name is used
If file name is an input (file name is not fixed)

 

Create (declare) the streams of type input or output to use them for reading a file or writing to a file.
ifstream inp_stream;    //create an input stream type
ofstream out_stream;  // create an output stream type

(A)
char inp_file[15], out_file[15];
(B)
Create (declare) the streams of type input or output to use them for reading a file or writing to a file.
ifstream inp_stream;    //create an input stream type
ofstream out_stream;  // create an output stream type

Step (3): Connect the input stream to an input file/the output stream to an output file
At this point you must be most careful. If, by mistake, you connect an out_stream to an input file, you can destroy the input file.
 
If fixed file name is used
If file name is an input (file name is not fixed)

 
 
 

inp_stream.open("input_file");
if(inp_stream.fail( ))
{
    cout << "Input file opening failed. \n";
    exit(1);   //exit the program
}

Similarly, for an input file we have:
out_stream.open("output_file");
if(out_stream.fail( ))
{
    cout << "Output file opening failed. \n";
    exit(1);   // exit the program
}

(A) 
cout << "Input the name of input file \n";
cin >> inp_file;

(B)
inp_stream.open(inp_file);
if(inp_stream.fail( ))
{
    cout << "Input file opening failed. \n";
    exit(1);   // exit the program
}

Similarly, for an input file we have:
out_stream.open(out_file);
if(out_stream.fail( ))
{
    cout << "Output file opening failed. \n";
    exit(1);   // exit the program
}

If you decide to append to an existing file, use:
outstream.open("output_file", ios::app);

Step (4): Use the input stream to read from the input file/the output stream to write the output file

To read:
inp_stream >> first_data >> second_data;

To write:
out_stream << first_data << second_data;

Step (5): Close the input and output files by disconnecting the corresponding streams
inp_stream.close( );
out_stream.close( );

Note that we have used two different methods to get a file name into the program.  In the method on the left hand side of the table in Steps (2) and (3), we have fixed input and/or output file names.  If the file name is different, the file name within " and " must be changed and the program must be recompiled for the new changes to become effective.  In the method on the right hand side of the table in Steps (2) and (3), we can ask for the file name when we run the program instead of editing and recompiling the program.  This method seems to be more convenient.

The following program reads a file containing some integer values (we do not know how many values).  It displays the number, the number to the power of two, and the sum up to that point. At last it displays the average of these numbers.

// P51.cpp - This program reads some integers from a file and displays:
// The number, number^2, and the sum of all numbers read up to that point
#include<iostream>
#include<fstream>  // Step (1)
#include<cstdlib>
#include<cmath>
using namespace std;

int main( )
{
    int x, count = 0;
    float sum = 0, avg;
    char input_file[15]; // Step (2)-A

    ifstream in_s;  // Step (2)-B - declaration of the stream of type input

 cout << "Please input the input file name \n"; // Step (3)-A Get the file name
 cin >> input_file;

    in_s.open(input_file); // Step (3)-B - connect to the input file and test
    if(in_s.fail( ))
    {
       cout << "Input file opening failed. \n";
       exit(1);  // if we couldn't open the file to read from we exit
    }

    cout << "\t  x \t\t x^2 \t\t Current Sum \n";
    cout << "\t === \t\t === \t\t ========== \n";

    while( in_s >> x) // Step (4)-Read all numbers one-by-one to the end of the file
    {
         sum = sum + x;
         cout << "\t  " << x <<"\t\t  " << pow(x,2) << "\t\t  " << sum << "\n";
   count++;
    }

 avg = sum/count;
 cout << "\n \t\t The average of these " << count << " numbers is: " << avg << endl;

    in_s.close( );  // Step (5)-Close the connection (close the file)

   return 0;
}

Every input or output file seems to have two names.  The actual names, or external file, is the name of the file as it appears on your computer disk.  The name of the stream used to read from/write to a file is referred to as internal file name.  The internal name is actually the name of the stream that you are using to read from/write to the input/output file.

Introduction to Classes and Objects
In C++ the streams cin, cout, and any other streams that you may declare are called objects.  You use the class ifstream to define objects of type ifstream and class ofstream to declare objects of type ofstream.  An object is a new type of variable that allows you to include functions, as well as data, in it.  An object may include several variables and functions of various types. In the above program, we have an object called in_s.  This object has several functions that were used in that program.  These functions are open(....), close( ), and fail( ).  The functions are called member functions.  Note that you would have similar functions for a stream of type output, but they may not have the same functionality as they are members of a different object type.  As you can see in the above program, the member functions are called using the dot operator (ex. in_s.close( ) ). The period between the in_s (calling object) and the close( ) (member function) is referred to as the dot operator.

Exercise 5.1
Carefully copy or cut and paste the program P51.cpp into a file called ex51.cpp.  Compile and run the program to make sure it compiles without any error.  Create a file, input.txt, and type the following 8 integers in it: 4 4 4 4 4 4 4 4.  Save the file and exit.  Now, run your program and when the program asks for the input file, type input.txt.  Your program should display an output similar to the one given below:

Please input the input file name.
input.txt
          x               x^2            Current Sum
        ===             ===          ==========
          4               16              4
          4               16              8
          4               16              12
          4               16              16
          4               16              20
          4               16              24
          4               16              28
          4               16              32

                 The average of these 8 numbers is: 4
This is the correct result.

Exercise 5.2
Modify the above program such that the program writes the output to a file called output.txt, instead of displaying it.