C++ File Input/Output
Practical C++ Programming, 2nd Edition
By Steve Oualline
http://www.oreilly.com/catalog/cplus2/?CMP=OT16469
O'Reilly & Associates, December 2002
ISBN: 0-596-00419-2
Chapter 16: File Input/Output
I am the heir of all the ages, in the foremost files of time.
--Tennyson
A file is a collection of related data. C++ treats a file as a series of bytes. Many files reside on disk; however, devices such as printers, magnetic tapes, and communication lines are also considered files.
This chapter discusses three different I/O packages. The first is the C++ I/O stream classes. This is the most commonly used I/O system and the one we've been using up to now. Next, we examine the raw I/O routines that give us direct access to the low-level I/O. Finally we look at the C I/O system. Although it is somewhat outdated, C I/O calls still appear in old code. Also, in some cases, the C-style I/O routines are superior to the ones provided with C++.
C++ File I/O
C++ file I/O is based on three classes: the istream class for input, the ostream class for output, and the iostream class for input/output. C++ refers to files as streams since it considers them a stream of bytes. Four class variables are automatically created when you start a program. These are listed in Table 16-1.
Variable |
Use |
---|---|
cin |
Console input (standard input) |
cout |
Console output (standard output) |
cerr |
Console error (standard error) |
clog |
Console log |
These variables are defined in the standard include file <iostream>. Normally, std::cin is assigned to the keyboard and std::cout, std::cerr, and std::clog are assigned to the screen. Most operating systems allow you to change these assignments through I/O redirection (see your operating system manual for details).
For example, the command:
my_prog <file.in
runs the program my_prog and assigns std::cin to the file file.in.
When doing I/O to disk files (except through redirection), you must use the file version of the stream classes. These are std::ifstream, std::ofstream, and std::fstream and are defined in the include file <fstream>.
Suppose you want to read a series of 100 numbers from the file numbers.dat. You start by declaring the input file variable:
std::ifstream data_file; // File we are reading the data from
Next you need to tell C++ what disk file to use. This is done through the open member function:
data_file.open("numbers.dat");
Now you can read the file using the same statements you've been using to read std::cin:
for (i = 0; i < 100; ++i) {
assert(i >= 0);
assert(i < sizeof(data_array)/sizeof(data_array[0]));
data_file >> data_array[i];
}
Finally you need to tell the I/O system that you are done with the file:
data_file.close( );
Closing the file frees resources that can then be used again by the program.
C++ allows the open call to be combined with the constructor. For example, instead of writing:
std::ifstream data_file; // File we are reading the data from
data_file.open("numbers.dat");
you can write:
std::ifstream data_file("numbers.dat"); // File we are reading the data from
Additionally, the destructor automatically calls close.
But what if the file numbers.dat is missing? How can you tell if there is a problem? The member function bad returns true if there is a problem, and false otherwise. So to test for problems, all you need is:
if (data_file.bad( )) {
std::cerr << "Unable to open numbers.dat\n";
exit (8);
}
A better version of the program for reading numbers is listed in Example 16-1.
Example 16-1: read/read.cpp
/********************************************************
* read -- read in 100 numbers and sum them *
* *
* Usage: *
* read *
* *
* Numbers are in the file "numbers.dat" *
* *
* Warning: No check is made for a file with less than *
* 100 numbers in it. *
********************************************************/
#include <iostream>
#include <fstream>
#include <cstdlib>
int main( )
{
const int DATA_SIZE = 100; // Number of items in the data
int data_array[DATA_SIZE]; // The data
std::ifstream data_file("numbers.dat"); // The input file
int i; // Loop counter
if (data_file.bad( )) {
std::cerr << "Error: Could not open numbers.dat\n";
exit (8);
}
for (i = 0; i < DATA_SIZE; ++i) {
assert(i >= 0);
assert(i < sizeof(data_array)/sizeof(data_array[0]));
data_file >> data_array[i];
}
int total; // Total of the numbers
total = 0;
for (i = 0; i < DATA_SIZE; ++i) {
assert(i >= 0);
assert(i < sizeof(data_array)/sizeof(data_array[0]));
total += data_array[i];
}
std::cout << "Total of all the numbers is " << total << '\n';
return (0);
}
If you want to read a line of data, you need to use the getline function. It is defined as:[1]
std::istream& getline(std::istream& input_file,
std::string& the_string);
std::istream& getline(std::istream& input_file,
std::string& the_string, char delim)
This function reads a line and stores it in a string. The function returns a reference to the input stream. The second form of the function allows you to specify your own end-of-line delimiter. If this is not specified, it defaults to newline ('\n'
).
Page 1 of 9
This article was originally published on March 20, 2003