Chapter 4 File
Chapter 4 File
The previous sections discussed in some detail how to get input from the keyboard (standard input
device) and send output to the screen (standard output device). However, getting input from the
keyboard and sending output to the screen have several limitations. Inputting data in a program from
the keyboard is comfortable as long as the amount of input is very small. Sending output to the screen
works well if the amount of data is small (no larger than the size of the screen) and you do not want
to distribute the output in a printed format to others.
If the amount of input data is large, however, it is inefficient to type it at the keyboard each time you
run a program. In addition to the inconvenience of typing large amounts of data, typing can generate
errors, and unintentional typos cause erroneous results. You must have some way to get data into the
program from other sources. By using alternative sources of data, you can prepare the data before
running a program, and the program can access the data each time it runs.
Suppose you want to present the output of a program in a meeting. Distributing printed copies of the
program output is a better approach than showing the output on a screen. For example, you might
give a printed report to each member of a committee before an important meeting. Furthermore,
output must sometimes be saved so that the output produced by one program can be used as an input
to other programs. This section discusses how to obtain data from other input devices, such as a disk
(that is, secondary storage), and how to save the output to a disk. C++ allows a program to get data
directly from and save output directly to secondary storage. A program can use the file I/O and read
data from or write data to a file. Formally, a file is defined as follows:
File: An area in secondary storage used to hold information.
A stream is a flow of characters (or other kind of data). If the flow is into your program, the stream is
called an input stream. If the flow is out of your program, the stream is called an output stream. If
the input stream flows from the keyboard, then your program will take input from the keyboard. If the
input stream flows from a file, then your program will take its input from that file. Similarly, an
output stream can go to the screen or to a file. Although you may not realize it, you have already been
using streams in your programs. The cin that you have already used is an input stream connected to
the keyboard, and cout is an output stream connected to the screen. These two streams are
automatically available to your program, as long as it has an include directive that names the header
file iostream. You can define other streams that come from or go to files; once you have defined
them, you can use them in your program in the same way you use the streams cin and cout.
The standard I/O header file, iostream, contains data types and variables that are used only for input
from the standard input device and output to the standard output device. In addition, C++ provides a
header file called fstream, which is used for file I/O. Among other things, the fstream header file
contains the definitions of two data types: ifstream, which means input file stream and is similar to
istream, and ofstream, which means output file stream and is similar to ostream.
The variables cin and cout are already defined and associated with the standard input/output devices.
In addition, >>, get, ignore, putback, peek, and so on can be used with cin, whereas <<, setfill, and so
on can be used with cout. These same operators and functions are also available for file I/O, but the
header file fstream does not declare variables to use them. You must declare variables called file
Fundamentals of Programming II
stream variables, which include ifstream variables for input and ofstream variables for output. You
then use these variables together with >>, <<, or other functions for I/O. Remember that C++ does
not automatically initialize user-defined variables. Once you declare the fstream variables, you must
associate these file variables with the input/output sources.
4.1. File I/O is a five-step process:
1. Include the header file fstream in the program.
2. Declare file stream variables.
3. Associate the file stream variables with the input/output sources.
4. Use the file stream variables with >>, <<, or other input/output functions.
5. Close the files.
We will now describe these five steps in detail. A skeleton program then shows how the steps might
appear in a program.
Step 1 requires that the header file fstream be included in the program. The following statement
accomplishes this task:
#include <fstream>
Step 2 requires you to declare file stream variables. Consider the following statements:
ifstream inData;
ofstream outData;
The first statement declares inData to be an input file stream variable. The second statement declares
outData to be an output file stream variable.
Step 3 requires you to associate file stream variables with the input/output sources. This step is called
opening the files. The stream member function open is used to open files.
fileStreamVariable.open(sourceName);
Here, fileStreamVariable is a file stream variable, and sourceName is the name of the input/output
file.
Suppose you include the declaration from Step 2 in a program. Further suppose that the input data is
stored in a file called prog.dat. The following statements associate inData with prog.dat and outData
with prog.out. That is, the file prog.dat is opened for inputting data, and the file prog.out is opened
for outputting data.
______________________________________________________________
Note: IDEs such as Visual Studio .Net manage programs in the form of projects. That is, first you
create a project, and then you add source files to the project. The statement in Line 1 assumes that the
Fundamentals of Programming II
file prog.dat is in the same directory (subdirectory) as your project. However, if this is in a different
directory (subdirectory), then you must specify the path where the file is located, along with the name
of the file. For example, suppose that the file prog.dat is on a flash memory in drive H. Then the
statement in Line 1 should be modified as follows:
inData.open("h:\\prog.dat");
Note that there are two \ after h:. In C++, \ is the escape character. Therefore, to produce a \within a
string, you need \\. (To be absolutely sure about specifying the source where the input file is stored,
such as the drive h:\\, check your system’s documentation.)
Similar conventions for the statement in Line 2.
______________________________________________________________
Note: We typically use .dat, .out, or .txt as an extension for the input and output files and use
Notepad, Wordpad, or TextPad to create and open these files. You can also use your IDE’s editor, if
any, to create .txt (text) files. (To be absolutely sure about it, check you IDE’s documentation.)
Step 4 typically works as follows. You use the file stream variables with >>, <<, or other input/output
functions. The syntax for using >> or << with file stream variables is exactly the same as the syntax
for using cin and cout. Instead of using cin and cout, however, you use the file stream variable names
that were declared. For example, the statement:
reads the data from the file prog.dat and stores it in the variable payRate. The statement:
outData << "The paycheck is: $" << pay << endl;
stores the output—The paycheck is: $565.78—in the file prog.out. This statement assumes that the
pay was calculated as 565.78.
Once the I/O is complete, Step 5 requires closing the files. Closing a file means that the file stream
variables are disassociated from the storage area and are freed. Once these variables are freed, they
can be reused for other file I/O. Moreover, closing an output file ensures that the entire output is sent
to the file; that is, the buffer is emptied. You close files by using the stream function close. For
example, assuming the program includes the declarations listed in Steps 2 and 3, the statements for
closing the files are:
inData.close();
outData.close();
______________________________________________________________
Note: On some systems, it is not necessary to close the files. When the program terminates, the files
are closed automatically. Nevertheless, it is a good practice to close the files yourself. Also, if you
want to use the same file stream variable to open another file, you must close the first file opened with
that file stream variable.
Fundamentals of Programming II
In skeleton form, a program that uses file I/O usually takes the following form:
#include <fstream>
int main()
{
//Declare file stream variables such as the following
ifstream inData;
ofstream outData;
.
.
.
//Open the files
inData.open("prog.dat"); //open the input file
outData.open("prog.out"); //open the output file
//Close files
inData.close();
outData.close();
return 0;
}
Recall that Step 3 requires the file to be opened for file I/O. Opening a file associates a file stream
variable declared in the program with a physical file at the source, such as a disk. In the case of an
input file, the file must exist before the open statement executes. If the file does not exist, the open
statement fails and the input stream enters the fail state. An output file does not have to exist before it
is opened; if the output file does not exist, the computer prepares an empty file for output. If the
designated output file already exists, by default, the old contents are erased when the file is opened.
Example:
//Reads three numbers from the file infile.dat, sums the numbers,
//and writes the sum to the file outfile.dat.
#include <fstream>
int main( )
{
using namespace std;
ifstream in_stream;
ofstream out_stream;
in_stream.open("infile.dat");
out_stream.open("outfile.dat");
int first, second, third;
Fundamentals of Programming II
in_stream >> first >> second >> third;
out_stream<< "The sum of the first 3\n"
<< "numbers in infile.dat\n"
<< "is " << (first + second + third)
<< endl;
in_stream.close( );
out_stream.close( );
return 0;
}
Every file should be closed when your program is finished getting input from the file or sending
output to the file. Closing a file disconnects the stream from the file. A file is closed with a call to the
function close. The following lines from the program in Display 6.1 illustrate how to use the function
close:
in_stream.close( );
out_stream.close( );
Notice that the function close takes no arguments. If your program ends normally but without closing
a file, the system will automatically close the file for you. However, it is good to get in the habit of
closing files for at least two reasons. First, the system will only close files for you if your program
ends in a normal fashion. If your program ends abnormally due to an error, the file will not be closed
and may be left in a corrupted state. If your program closes files as soon as it is finished with them,
file corruption is less likely. A second reason for closing a file is that you may want your program to
send output to a file and later read that output back into the program. To do this, your program should
close the file after it is finished writing to the file, and then your program should connect the file to an
input stream using the function open. (It is possible to open a file for both input and output, but this is
done in a slightly different way and we will not be discussing this alternative.)
A call to open can be unsuccessful for a number of reasons. For example, if you open an input file
and there is no file with the external name that you specify, then the call to open will fail. When this
happens, you might not receive an error message and your program might simply proceed to do
something unexpected. Thus, you should always follow a call to open with a test to see whether the
Fundamentals of Programming II
call to open was successful and to end the program (or take some other appropriate action) if the call
to open was unsuccessful.
fail ( )
You can use the member function named fail to test whether a stream operation has failed. There is a
member function named fail for each of the classes ifstream and ofstream. The fail function takes no
arguments and returns a bool value. A call to the function fail for a stream named in_stream would be
as follows:
in_stream.fail()
This is a Boolean expression that can be used to control a while loop or an if-else statement. You
should place a call to fail immediately after each call to open; if the call to open fails, the function fail
will return true (that is, the Boolean expression will be satisfied). For example, if the following call to
open fails, then the program will output an error message and end; if the call succeeds, the fail
function returns false, so the program will continue.
in_stream.open("stuff.dat");
if (in_stream.fail())
{
cout << "Input file opening failed.\n";
exit(1);
}
fail is a member function, so it is called using the stream name and a dot. Of course, the call to
in_stream.fail refers only to a call to open of the form in_stream.open, and not to any call to the
function open made with any other stream as the calling object.
The exit statement shown ealier has nothing to do with classes and has nothing directly to do with
streams, but it is often used in this context. The exit statement causes your program to end
immediately. The exit function returns its argument to the operating system. To use the exit
statement, your program must contain the following include directive:
#include <cstdlib>
When using exit, your program must also contain the following, normally either at the start of the file
or at the start of the function body that uses exit:
//Reads three numbers from the file infile.dat, sums the numbers,
//and writes the sum to the file outfile.dat.
#include <fstream>
#include <iostream>
#include <cstdlib>
int main()
Fundamentals of Programming II
{
using namespace std;
ifstream in_stream;
ofstream out_stream;
in_stream.open("infile.dat");
if (in_stream.fail())
{
cout << "Input file opening failed.\n";
exit(1);
}
out_stream.open("outfile.dat");
if (out_stream.fail())
{
cout << "Output file opening failed.\n";
exit(1);
}
int first, second, third;
in_stream.close();
out_stream.close();
return 0;
}
When sending output to a file, your code must first use the member function open to open a file and
connect it to a stream of type ofstream. The way we have done that thus far (with a single argument
for the file name) always gives an empty file. If a file with the specified name already exists, its old
contents are lost. There is an alternative way to open a file so that the output from your program will
be appended to the file after any data already in the file.
To append your output to a file named important.txt, you would use a two-argument version of open,
as illustrated by the following:
If the file important.txt does not exist, this will create an empty file with that name to receive your
program’s output, but if the file already exists, then all the output from your program will be
appended to the end of the file, so that old data in the file is not lost.
Fundamentals of Programming II
The second argument ios::app is a special constant that is defined in iostream and so requires the
following include directive:
#include <iostream>
Your program should also include the following, normally either at the start of the file or at the start
of the function body that uses ios::app:
This can sometimes be inconvenient. For example, the program in the above reads numbers from the
file infile.dat and outputs their sum to the file outfile.dat. If you want to perform the same
calculation on the numbers in another file named infile2.dat and write the sum of these numbers to
another file named outfile2.dat, then you must change the file names in the two calls to the member
function open and then recompile your program. A preferable alternative is to write your program so
that it asks the user to type in the names of the input and output files. This way your program can use
different files each time it is run.
A file name is a string. However, it is easy to learn enough about strings so that you can write
programs that accept a file name as input. A string is just a sequence of characters. We have already
used string values in output statements such as the following:
cout << "This is a string.";
We have also used string values as arguments to the member function open. Whenever you write a
literal string, as in the cout statement shown, you must place the string in double quotes.
In order to read a file name into your program, you need a variable that is capable of holding a string.
A variable to hold a string value is declared as in the following example:
char file_name[16];
This declaration is the same as if you had declared the variable to be of type char, except that the
variable name is followed by an integer in square brackets that specifies the maximum number of
characters you can have in a string stored in the variable. This number must be one greater than the
maximum number of characters in the string value. So, in our example, the variable file_name can
contain any string that contains 15 or fewer characters. The name file_name can be replaced by any
other identifier (that is not a keyword), and the number 16 can be replaced by any other positive
integer.
You can input a string value to a string variable the same way that you input values of other types.
For example, consider the following piece of code:
Fundamentals of Programming II
cout << "Enter the file name (maximum of 15 characters):\n";
cin >> file_name;
cout << "OK, I will edit the file " << file_name << endl;
Once your program has read the name of a file into a string variable, such as the variable file_name, it
can use this string variable as the argument to the member function open. For example, the following
will connect the input-file stream in_stream to the file whose name is stored in the variable file_name
(and will use the member function fail to check whether the opening was successful):
ifstream in_stream;
in_stream.open(file_name);
if (in_stream.fail( ))
{
cout << "Input file opening failed.\n";
exit(1);
}
Note that when you use a string variable as an argument to the member function open, you do not use
any quotes.
Example
//Reads three numbers from the file specified by the user, sums the numbers,
//and writes the sum to another file specified by the user.
#include <fstream>
#include <iostream>
#include <cstdlib>
int main( )
{
using namespace std;
char in_file_name[16], out_file_name[16];
ifstream in_stream;
ofstream out_stream;
cout << "I will sum three numbers taken from an input\n"
<< "file and write the sum to an output file.\n";
cout << "Enter the input file name (maximum of 15 characters):\n";
cin >> in_file_name;
cout << "Enter the output file name (maximum of 15 characters):\n";
cin >> out_file_name;
cout << "I will read numbers from the file "
<< in_file_name << " and\n"
<< "place the sum in the file "
<< out_file_name << endl;
in_stream.open(in_file_name);
if (in_stream.fail( ))
{
Fundamentals of Programming II
cout << "Input file opening failed.\n";
exit(1);
}
out_stream.open(out_file_name);
if (out_stream.fail( ))
{
cout << "Output file opening failed.\n";
exit(1);
}
in_stream.close( );
out_stream.close( );
Sample Dialogue
A stream can be an argument to a function. The only restriction is that the function formal parameter
must be call-by-reference. A stream parameter cannot be a call-by-value parameter. For example,
the function make_neat in the following example has two stream parameters: one is of type ifstream
Fundamentals of Programming II
and is for a stream connected to an input file; another is of type ofstream and is for a stream
connected to an output file. We will discuss the other features of the program in Display 6.6 in the
next two subsections.
Example:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <iomanip>
int main( )
{
ifstream fin;
ofstream fout;
fin.open("rawdata.dat");
if (fin.fail( ))
{
cout << "Input file opening failed.\n";
exit(1);
}
fout.open("neat.dat");
if (fout.fail( ))
{
cout << "Output file opening failed.\n";
exit(1);
}
fin.close( );
fout.close( );
Fundamentals of Programming II
{
double next;
while (messy_file >> next)
{
cout << setw(field_width) << next << endl;
neat_file << setw(field_width) << next << endl;
}
}
Every input-file stream has a member function called eof that can be used to determine when all of
the file has been read and there is no more input left for the program. This is the second technique we
have presented for determining when a program has read everything in a file.
The letters eof stand for end of file, and eof is normally pronounced by saying the three letters e-o-f.
The function eof takes no arguments, so if the input stream is called fin, then a call to the function eof
is written fin.eof( )
This is a Boolean expression that can be used to control a while loop, a do-while loop, or an if-else
statement. This expression is satisfied (that is, is true), if the program has read past the end of the
input file; otherwise, the above expression is not satisfied (that is, is false).
Since we usually want to test that we are not at the end of a file, a call to the member function eof is
typically used with a not in front of it. Recall that in C++ the symbol ! is used to express not. For
example, consider the following statement:
if (! fin.eof( ))
cout << "Not done yet.";
else
cout << "End of the file.";
The Boolean expression after the if means “not at the end of the file connected to fin.” Thus, the
above if-else statement will output the following to the screen:
provided the program has not yet read past the end of the file that is connected to the stream fin. The
if-else statement will output the following, if the program has read beyond the end of the file:
As another example of using the eof member function, suppose that the input stream in_stream has
been connected to an input file with a call to open. Then the entire contents of the file can be written
to the screen with the following while loop:
in_stream.get(next);
while (! in_stream.eof( ))
Fundamentals of Programming II
{
cout << next;
in_stream.get(next);
}
Fundamentals of Programming II
QUICK REVIEW
Fundamentals of Programming II