C++ has a rich I/O library, which is often called I/O streams . This chapter presents an overview of the C++ I/O library. For details of individual classes and functions, see Chapter 13. The I/O streams often use templates; refer to Chapter 7 for information about templates. See also Chapter 8 for information about character traits.
The standard I/O streams can also be used with standard iterator adapters. See Chapter 10 for details.
As with C and many modern languages, input and output in C++ is implemented entirely in the library. No language features specifically support I/O.
The C++ I/O library is based on a set of templates parameterized
on the character type. Thus, you can read and write plain char
-type characters, wide wchar_t
characters, or some other, exotic
character type that you might need to invent. (Read about character
traits in Chapter 8 first.) Figure 9-1 depicts the class
hierarchy. Notice that the names are of the form basic_
name
. These
are the template names; the specializations have the more familiar names
(e.g., istream
specializes basic_istream<char>
).
One advantage of using inheritance in the I/O library is that the basic I/O functions are defined once in the base classes, and that interface is inherited by the derived classes and overridden when necessary. Using inheritance, you perform I/O with files as you would with strings. With only a little effort, you can derive your own I/O classes for specialized situations. (See Example 9-6.) Thus, to understand I/O in C++, you must start with the base classes.
Another advantage of the I/O stream classes is that you can implement your own overloaded functions that look and behave like the standard functions. Thus, you can read and write objects of your custom classes just as easily as the fundamental types.
The ios_base
class declares types and constants that are used
throughout the I/O library. Formatting flags, I/O state flags, open
modes, and seek directions are all declared in ios_base
.
The basic_istream
template declares input functions, and basic_ostream
declares output functions. The basic_iostream
template inherits input and
output functions through multiple inheritance from basic_istream
and basic_ostream
.
The stream class templates handle high-level I/O of numbers,
strings, and characters. For low-level I/O, the streams rely on
stream buffers , which control reading and writing buffers of characters.
The basic_streambuf
template defines the stream buffer interface, and the
actual behavior is implemented by derived-class templates.
I/O to and from external files is handled by basic_fstream
, basic_ifstream
, and basic_ofstream
, using basic_filebuf
as the stream buffer. These class templates are declared in <fstream>
.
You can also treat a string as a stream using basic_istringstream
, basic_ostringstream
,
and basic_stringstream
. The stream
buffer template is basic_stringbuffer
. These class templates are
declared in <sstream>
.
The I/O library supports formatted and unformatted I/O. Unformatted I/O simply reads or writes characters or character strings without interpretation. The I/O streams have a number of functions for performing unformatted I/O.
Formatted input can skip over leading whitespace, parse text as numbers, and interpret numbers in different bases (decimal, octal, hexadecimal). Formatted output can pad fields to a desired width and write numbers as text in different bases. Formatted I/O uses a stream's locale to parse numeric input or format numeric output.
A locale is an object of type locale
. It stores character attributes,
formatting preferences, and related information about a particular
culture or environment. This information is organized into a set of
facets . For example, the num_get
facet defines how numbers are read and parsed from an
input stream; the num_put
facet
defines how numbers are formatted and written to an output stream; and
the numpunct
facet specifies the
punctuation characters used for decimal points, minus signs, and so on.
Locales are used primarily by I/O streams, but they have other uses, as
well. See <locale>
in Chapter 13 for details.
To perform formatted I/O, the I/O streams overload the shift
operators: left shift (<<
)
writes and right shift (>>
)
reads. Think of the shift operators as arrows pointing in the direction of
data flow: output flows from an expression to the stream (cout
<<
expr
). Input flows from the stream to a
variable (cin
>>
var
). The string
, complex
, and other types in the standard
library overload the shift operators, so you can perform I/O with these
objects just as easily as you can with the fundamental types.
When you define your own classes for which I/O is
meaningful, you should also override the shift operators to perform
I/O in the same manner as the standard I/O operators. A common
simplification is to overload the shift operators for istream
and ostream
, but that prevents your operators
from being used with wide-character streams or streams with custom
character traits. You should consider writing function templates
instead, using basic_istream
and
basic_ostream
, to take advantage of
the generality that the I/O stream templates offer.
Other guidelines to follow when writing custom I/O functions are:
Pay attention to the stream's flags, locale, and state.
Set failbit
for malformed
input.
Be careful with internal whitespace.
When writing an object that has multiple parts, be careful
of how you treat the stream's field width. Remember that the width
is reset to 0
after each
formatted output function.
Example 9-1 shows an
example of I/O for the rational
class, which represents a rational number. For input, two numbers are
read, separated by a slash (/
). If
the slash is missing, the input is malformed, so failbit
is set. (See the <ios>
header in Chapter 13 for more information about
failbit
and the other state bits.)
For output, the two parts of the rational number are formatted as a
string, and the entire string is written to the output stream. Using a
temporary string lets the caller set the field width and apply the
width to the entire rational number as a single entity. If the
numerator and denominator were written directly to the output stream,
the width would apply only to the numerator. (See Example 9-3 for more information
about rational
.)
Example 9-1. Performng I/O with the rational class template
// Read a rational number. The numerator and denominator must be written as two // numbers (the first can be signed) separated by a slash (/). For example: // "2/3", "-14/19". template<typename T, typename charT, typename traits> std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& in, rational<T>& r) { typename rational<T>::numerator_type n; typename rational<T>::denominator_type d; char c; if (! (in >> n)) return in; // Allow whitespace before and after the dividing '/'. if (! (in >> c)) return in; if (c != '/') { // Malformed input in.setstate(std::ios_base::failbit); return in; } if (! (in >> d)) return in; r.set(n, d); return in; } // Write a rational number as two integers separated by a slash. Use a string // stream so the two numbers are written without padding, and the overall // formatted string is then padded to the desired width. template<typename T, typename charT, typename traits> std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out, const rational<T>& r) { // Use the same flags, locale, etc. to write the // numerator and denominator to a string stream. std::basic_ostringstream<charT, traits> s; s.flags(out.flags( )); s.imbue(out.getloc( )); s.precision(out.precision( )); s << r.numerator( ) << '/' << r.denominator( ); // Write the string to out. The field width, padding, and alignment are already // set in out, so they apply to the entire rational number. out << s.str( ); return out; }
Because the C++ library includes the C library, you can use any
of the C standard I/O functions, such as fopen
and printf
. The C standard I/O library is
contained in <cstdio>
for
narrow I/O and <cwchar>
for
wide-character I/O. The C++ library inherits many attributes from the
C library. For example, the C++ end-of-file marker, char_traits<char>::eof( )
, has the
same value as the C end-of-file marker, EOF
. In most cases, however, a C++ program
should use C++ I/O functions rather than C functions.
The printf
and scanf
functions
are noteworthy for their lack of safety. Although some compilers now
check the format strings and compare them with the actual arguments,
many compilers do not. It is too easy to make a simple mistake. If you
are lucky, your program will fail immediately. If you are unlucky,
your program will appear to work on your system and fail only when it
is run on your customers' systems. The following is an example of a
common mistake made when using printf
:
size_t s; printf("size=%u\n", s);
The problem here is that the size_t
type might be unsigned
long
, which means the argument s
and the format %u
do not match. On some systems, the
mismatch is harmless, but on others, wrong information will be
printed, or worse.
Other functions, such as gets
and sprintf
, are unsafe because
they write to character arrays with no way to limit the number of
characters written. Without a way to prevent buffer overruns, these
functions are practically useless.
Another limitation of the C I/O library is that it has little
support for alternate locales. In C++, every stream can have a
different locale. For example, this lets you write a program that
reads a datafile in a fixed format (using the "C
" locale), but prints the human-readable
results in the native locale. Writing such a program using the C I/O
library requires that locales be changed between each read and write
call, which is much less convenient.
In spite of all these problems, some C++ programmers still use
the C library. In some implementations, the C library performs better
than the C++ library. Another reason is that some C++ functions, such
as printf
, have a brevity that
appeals to C and C++ programmers. Compare the following examples, one
using printf
and the other using
the <<
operator, which both
print the same count
and mask
values in the same formats:
unsigned long count, mask; ... printf("count=%-9.9ld\n" "mask=%#-8.8lx\n", count, mask); cout.fill('0'); cout << "count=" << right << dec << setw(9) << count << "\nmask=0x" << hex << setw(8) << mask << '\n';
Even though the printf
approach seems more concise and easier to understand, I recommend
using the C++ I/O streams. You might think printf
is saving you time now, but the lack
of safety can present major problems in the future. (Reread the
example and imagine what would happen if count
exceeded the maximum value for type
long
.)
Sometimes, using the C I/O library is necessary (e.g., perhaps
legacy C code is being called from C++ code). To help in such
situations, the standard C++ I/O objects are associated with their
corresponding C FILE
s. The C++
cin
object is associated with the C
stdin
object, cout
is associated with stdout
, and cerr
and clog
are associated with stderr
. You can mix C and C++ I/O functions
with the standard I/O objects.
This section lists the I/O-related headers in the C++ standard library, with a brief description of each. See the corresponding sections in Chapter 13 for more detailed descriptions.
<fstream>
File streams—that is, input and output using external
files. Declares basic_filebuf
, basic_fstream
, basic_ifstream
, basic_ofstream
, fstream
, ifstream
, ofstream
, wfstream
, wistream
, wostream
, and other types.
<iomanip>
Declares several manipulators—that is, function objects that affect an I/O stream object. A manipulator offers an alternate, often more convenient, syntax for calling member functions of an I/O stream object.
<ios>
Base template definitions of ios_base
, basic_ios
and some common
manipulators. All I/O streams derive from basic_ios
, which derives from ios_base
.
<iosfwd>
Forward declarations of the standard I/O classes and
templates. Judicious use of <iosfwd>
can reduce the
compile-time burden in certain situations.
<iostream>
Declarations of the standard I/O objects: cin
, cout
, etc.
<istream>
Declares types and functions for input-only streams
(basic_istream
, istream
, and wistream
), and for input and output
streams (basic_iostream
,
iostream
, and wiostream
).
<ostream>
Declares types and functions for output-only streams
(basic_ostream
, ostream
, and wostream
).
<sstream>
Declares string streams (basic_istringstream
, basic_ostringstream
, basic_stringbuf
, basic_stringstream
, istringstream
, ostringstream
, and stringstream
), which read from and
write to strings using the stream protocol.
<streambuf>
Declares low-level stream buffers (basic_streambuf
) for the I/O stream
classes. Most programs do not need to deal with the stream
buffers, but stick to the high-level interfaces presented by the
stream classes.
<strstream>
Declares string streams (istrstream
, ostrstream
, strstream
, strstreambuf
), which read and write to
character arrays using a stream protocol. These classes are not
template-based so they do not work for wide characters or
alternative character traits. This header is deprecated.