Chapter 4: File Operations (File Input/output)
4.1. Introduction
I/O refers to program input and output. Input can be taken from the keyboard or from a file.
Similarly, output can be sent to the screen or to a file. Input is delivered to your program via a
C++ construct known as a stream, and output from your program is delivered to the output
device via a stream. Streams are our first examples of objects. An object is a special kind of
variable that has its own special-purpose functions that are, in a sense, attached to the
variable. The ability to handle objects is one of the language features that sets C++ apart from
earlier programming languages.
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 keyboard input and screen output we have used so far deal with temporary data. When
the program ends, the data typed in at the keyboard and the data left on the screen go away.
Files provide you with a way to store data permanently. The contents of a file remain until a
person or program changes the file. If your program sends its output to a file, the output file
will remain after the program has finished running. An input file can be used over and over
again by many programs without the need to type in the data separately for each program.
This means you can create an input file for your program or read an output file produced by
your program whenever it's convenient for you, as opposed to having to do all your reading
and writing while the program is running. Files also provide you with a convenient way to
deal with large quantities of data. When your program takes its input from a large input file,
your program receives a lot of data without making the user do a lot of typing.
4.2. Stream classes
The streams cin and cout are already declared for you, but if you want a stream to connect to
a file, you must declare it just as you would declare any other variable. The type for input-file
stream variables is named ifstream (for "input-file stream"). The type for output-file stream
variables is named ofstream (for "output-file stream"). Fstream is used to both read and write
from and in to file. Thus, you can declare in_stream to be an input stream for a file and
out_stream to be an output stream for another file as follows:
ifstream in_stream;
ofstream out_stream;
The types ifstream and ofstream are defined in the library with the header file fstream, and so
any program that declares stream variables in this way must contain the following directive
(normally near the beginning of the file):
#include <fstream>
When using the types ifstream and ofstream, 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 the types
ifstream or ofstream:
using namespace std;
Stream variables, such as in_stream and out_stream declared earlier, must each be connected
to a file. This is called opening the file and is done with a function named open. The function
open contains two arguments file name and mode. The file name parameter denotes the name
of the file to open and the mode parameter is optional and takes one of the following formats.
ios::app - is append mode and the output sent to the file is appended to it
ios::ate - opens the file for the output then moves the read and write control to the file’s end.
ios::app - opens the file for a read mode.
ios::out - opens the file for a write.
ios::trunc – if a file exists, the elements should be truncated prior to its opening.
For example, suppose you want the input stream in_stream connected to the file named
[Link]. Your program must then contain the following before it reads any input from this
file:
in_stream.open("[Link]", ios::out);
If the input file is in the same directory as your program, you probably can simply give the
name of the file in the manner just described. In some situations you might also need to
specify the directory that contains the file. The details about specifying directories vary from
one system to another. Once you have declared an input stream variable and connected it to a
file using the open function, your program can take input from the file using the extraction
operator ».
For example, the following reads two input numbers from the file connected to in_stream and
places them in the variables [Link] and [Link]:
int [Link], [Link];
in_stream » [Link] » [Link];
An output stream is opened (that is, connected to a file) in the same way as just described for
input streams.
Example 1 - the following code declares the output stream “ouf” in out mode and connects it
to the file named [Link] and writes the numbers 1 and 2 to the file.
Example 1 - the following code declares the output stream “ouf” in “app” mode and
connects it to the file named [Link] and appends the numbers 3 and 4 to the file.
When used with a stream of type ofstream, the member function open will create the output
file if it does not already exist. If the output file does already exist, the member function open
will discard the contents of the file, so that the output file is empty after the call to open.
After a file is connected to the stream ouf with a call to open, the program can send output to
that file using the insertion operator «. 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 streams inf and ouf found in the above program and the predefined streams cin and cout
are objects. An object is a variable that has functions as well as data associated with it. For
example, the streams inf and ouf both have a function named open associated with them. A
function that is associated with an object is called a member function. A type whose
variables are objects—such as ifstream and ofstream—is called a class. When you call a
member function in a program, you always specify an object, usually by writing the object
name and a dot before the function name, as in the following example:
[Link]("[Link]");
You can use the member function named fail to test whether a stream function fail 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 inf would be as follows:
[Link]("[Link]");
if ([Link]( ))
{
cout « "Input file opening failed.\n";
exit(l);
}
To use the exit statement, your program must contain the following include directive:
#include <cstdlib>
Every input-file stream has a member function called eof that can be used to test for reaching
the end of the input file. The function eof takes no arguments. For example, the entire
contents of the file connected to the input stream inStream can be written to the screen with
the following while loop:
Thus far, we have written the literal file names for our input and output files into the code of
our programs by giving the file name as the argument to a call to the function open. You can
instead read the file name in from the keyboard, as illustrated by the following:
4.3. Stream buffer
The streambuf layer provides buffering capability and hides the details of physical IO device
handling. Under normal circumstances, the user need not worry about or directly work with
streambuf objects. These are indirectly employed by streams. Think of a streambuf as a
sequence of characters which can grow or shrink. All stream classes contain a pointer to a
streambuf object or one derived from it. Depending on the type of the stream, one or two
pointers are associated with this sequence.
A put pointer points to the position of the next character to be deposited into the
sequence as a result of an insertion.
A get pointer points to the position of the next character to be fetched from the
sequence as a result of an extraction.
ofstream only has a put pointer, ifstream only has a get pointer, and fstream has both
pointers.
An output stream can be flushed by invoking its flush member function. Flushing causes any
buffered data to be immediately sent to output.
The position of an output stream put pointer can be queried using tellp and adjusted using
seekp.
[Link]([Link]() + 10);
moves the put pointer 10 characters forward. An optional second argument to seekp enables
the position to be specified relatively rather than absolutely.
The second argument may be one of the following:
· ios::beg for positions relative to the beginning of the stream,
· ios::cur for positions relative to the current put pointer position, or
· ios::end for positions relative to the end of the stream.
Example 1:
The position of an input stream get pointer can be queried using tellg and adjusted using
seekg.
For example,
[Link]([Link]() - 10);
moves the get pointer 10 characters backward. An optional second argument to seekg enables
the position to be specified relatively rather than absolutely.
For example, the above is equivalent to:
[Link](-10, ios::cur);
As with seekp, the second argument may be one of ios::beg, ios::cur, or ios::end.