Don't hesitate to send in feedback: send an e-mail if you like the C++ Annotations; if you think that important material was omitted; if you find errors or typos in the text or the code examples; or if you just feel like e-mailing. Send your e-mail to Frank B. Brokken.Please state the document version you're referring to, as found in the title (in this document: 7.2.0) and please state chapter and paragraph name or number you're referring to.
All received mail is processed conscientiously, and received suggestions for improvements will usually have been processed by the time a new version of the Annotations is released. Except for the incidental case I will normally not acknowledge the receipt of suggestions for improvements. Please don't interpret this as me not appreciating your efforts.
As an extension to the standard stream (
FILE) approach, well known from the
C programming language, C++ offers an input/output (
I/O)
library
based on class concepts.
Earlier (in chapter 3) we've already seen examples of the use of the C++ I/O library, especially the use of the insertion operator (<<) and the extraction operator (>>). In this chapter we'll cover the library in more detail.
The discussion of input and output facilities provided by the C++
programming language heavily uses the class concept, and the notion of
member functions. Although the construction of classes will be covered in the
upcoming chapter 6, and inheritance will formally be introduced
in chapter 13, we think it is quite possible to introduce input
and output (I/O) facilities long before the technical background of
these topics is actually covered.
Most C++ I/O classes have names starting with
basic_ (like
basic_ios). However, these
basic_ names are not regularly found in
C++ programs, as most classes are also defined using
typedef
definitions like:
typedef basic_ios<char> ios;
Since C++ defines both the
char and
wchar_t types, I/O
facilities were developed using the
template mechanism. As will be
further elaborated in chapter 18, this way it was possible to
construct
generic software, which could thereupon be used for both the
char and wchar_t types. So, analogously to the above typedef there
exists a
typedef basic_ios<wchar_t> wios;
This type definition can be used for the wchar_t type. Because of the
existence of these type definitions, the basic_ prefix can be omitted from
the Annotations without loss of continuity. In the Annotations the emphasis is
primarily on the standard 8-bits char type.
As a side effect to this implementation it must be stressed that it is not anymore correct to declare iostream objects using standard forward declarations, like:
class ostream; // now erroneous
Instead, sources that must
declare iostream classes must
#include <iosfwd> // correct way to declare iostream classes
Using the C++ I/O library offers the additional advantage of
type safety. Objects (or plain values) are inserted into
streams. Compare this to the situation commonly encountered in C where the
fprintf() function is used to indicate by a format string what kind of
value to expect where. Compared to this latter situation C++'s
iostream approach immediately uses the objects where their values should
appear, as in
cout << "There were " << nMaidens << " virgins present\n";
The compiler notices the type of the nMaidens variable, inserting
its proper value at the appropriate place in the sentence inserted into
the cout iostream.
Compare this to the situation encountered in C. Although C compilers
are getting smarter and smarter over the years, and although a well-designed
C compiler may warn you for a mismatch between a format specifier and the
type of a variable encountered in the corresponding position of the argument
list of a
printf() statement, it can't do much more than warn you.
The type safety seen in C++ prevents you from making type
mismatches, as there are no types to match.
Apart from this, iostreams offer more or less the same set of
possibilities as the standard FILE-based I/O used in C: files can be
opened, closed, positioned, read, written, etc.. In C++ the basic FILE
structure, as used in C, is still available. C++ adds I/O based on
classes to FILE-based I/O, resulting in type safety, extensibility, and a
clean design. In the
ANSI/ISO standard the intent was to construct
architecture independent I/O. Previous implementations of the iostreams
library did not always comply with the standard, resulting in many extensions
to the standard. Software developed earlier may have to be partially rewritten
with respect to I/O. This is tough for those who are now forced to modify
existing software, but every feature and extension that was available in
previous implementations can be reconstructed easily using the ANSI/ISO
standard conforming I/O library. Not all of these re-implementations
can be covered in this chapter, as most use inheritance and polymorphism,
topics that will be covered in chapters 13 and
14, respectively. Selected re-implementations will be provided
in chapter 21, and below references to particular sections in that
chapter will be given where appropriate.

This chapter is organized as follows (see also Figure 3):
class
ios_base is the foundation upon which the
iostreams I/O library was built. It defines the core of all I/O operations and
offers, among other things, facilities for inspecting the
state of I/O streams and for
output formatting.
ios was directly derived from ios_base. Every
class of the I/O library doing input or output is derived from this
ios class, and inherits its (and, by implication, ios_base's)
capabilities. The reader is urged to keep this feature in mind while reading
this chapter. The concept of inheritance is not discussed further here, but
rather in chapter 13.
An important function of the class ios is to define the communication with
the
buffer that is used by streams. The buffer is a
streambuf object
(or is derived from the class streambuf) and is responsible for the actual
input and/or output. This means that iostream objects do not perform
input/output operations themselves, but leave these to the (stream)buffer
objects with which they are associated.
ostream, defining the
insertion operator as
well as other facilities for writing information to streams. Apart from
inserting information in files it is possible to
insert information in memory buffers, for which the
ostringstream
class is available. Formatting of the output is to a great extent possible
using the facilities defined in the ios class, but it is also possible to
insert formatting commands directly in streams using
manipulators. This aspect of C++ output is discussed as well.
istream
class. This class defines the
insertion operator and related facilities for
input. Analogous to the ostringstream a class
istringstream class is
available for
extracting information from memory buffers.
filebuf ojects. Other I/O
related topics are covered elsewhere in the Annotations, e.g., in chapter
21.
streambuf, which is responsible for the actual
input and output to the
device for which the streambuf object was
created in the first place. This approach allows us to construct a new kind of
streambuf for a new kind of device, and use that streambuf in combination
with the `good old' istream- or ostream-class facilities. It is
important to understand the distinction between the formatting roles of the
iostream objects and the buffering interface to an external device as
implemented in a streambuf. Interfacing to new devices (like
sockets
or
file descriptors) requires us to construct a new kind of streambuf,
not a new kind of istream or ostream object. A
wrapper class may
be constructed around the istream or ostream classes, though, to ease
the access to a special device. This is how the stringstream classes were
constructed.
#include <iosfwd>: sources should use this
preprocessor directive
if a forward declaration is required for the iostream classes. For example,
if a function defines a reference parameter to an ostream then, when this
function itself is declared, there is no need for the compiler to know exactly
what an ostream is. In the header file declaring such a function the
ostream class merely needs to be be declared. One cannot use
class ostream; // erroneous declaration
void someFunction(ostream &str);
but, instead, one should use:
#include <iosfwd> // correctly declares class ostream
void someFunction(ostream &str);
#include <streambuf>: sources should use this preprocessor directive
when using streambuf or
filebuf classes. See sections 5.7
and 5.7.2.
#include <istream>: sources should use this preprocessor directive
when using the class istream or when using classes that do both input and
output. See section 5.5.1.
#include <ostream>: sources should use this
preprocessor directive
when using the class
ostream class or when using classes that do both
input and output. See section 5.4.1.
#include <iostream>: sources should use this preprocessor directive
when using the global stream objects (like
cin and
cout).
#include <fstream>: sources should use this preprocessor directive
when using the file stream classes. See sections
5.4.2, 5.5.2, and 5.8.4.
#include <sstream>: sources should use this preprocessor directive
when using the string stream classes. See sections 5.4.3 and
5.5.3.
#include <iomanip>: sources should use this preprocessor directive
when using parameterized manipulators. See section 5.6
ios_base forms the foundation of all I/O operations, and
defines, among other things, the facilities for inspecting the
state of I/O streams and most
output formatting facilities. Every
stream class of the I/O library is, via the class
ios, derived from
this class, and inherits its capabilities.
The discussion of the class ios_base precedes the introduction of members
that can be used for actual reading from and writing to streams. But as the
ios_base class is the foundation on which all I/O in C++ was built, we
introduce it as the first class of the C++ I/O library.
Note, however, that as in C, I/O in C++ is not part of the
language (although it is part of the
ANSI/ISO standard on C++):
although it is technically possible to ignore all predefined I/O facilities,
nobody actually does so, and the I/O library represents therefore a
de facto I/O standard in C++. Also note that, as mentioned before,
the iostream classes do not do input and output themselves, but delegate this
to an auxiliary class: the class
streambuf or its derivatives.
For the sake of completeness it is noted that it is not
possible to construct an ios_base object directly. As covered by chapter
13, classes that are derived from ios_base (like ios)
may construct ios_base objects using the
ios_base::ios_base()
constructor.
The next class in the iostream hierarchy (see figure 3) is the
class
ios. Since the stream classes inherit from the class ios, and
thus also from ios_base, in practice the distinction between ios_base
and
ios is hardly important. Therefore, facilities actually provided by
ios_base will be discussed as facilities provided by ios. The reader
who is interested in the true class in which a particular facility is defined
should consult the relevant header files (e.g.,
ios_base.h and
basic_ios.h).
ios class was derived directly from
ios_base, and it defines de
facto the foundation for all stream classes of the C++ I/O library.
Although it is possible to construct an ios object
directly, this is hardly ever done. The purpose of the class ios is to
provide the facilities of the class basic_ios, and to add several new
facilites, all related to managing the streambuf object which is managed
by objects of the class ios.
All other stream classes are either directly or indirectly derived from
ios. This implies, as explained in chapter 13, that all
facilities offered by the classes ios and ios_base are also available
in other stream classes. Before discussing these additional stream classes,
the facilities offered by the class ios (and by implication: by
ios_base) are now introduced.
The class ios offers several member functions, most of which are related
to
formatting. Other frequently used member functions are:
streambuf *ios::rdbuf():This member function returns a pointer to thestreambufobject forming the interface between theiosobject and the device with which theiosobject communicates. See section 21.2.2 for further information about theclass streambuf.
streambuf *ios::rdbuf(streambuf *new):
This member function can be used to associate aiosobject with anotherstreambufobject. A pointer to theiosobject's originalstreambufobject is returned. The object to which this pointer points is not destroyed when thestreamobject goes out of scope, but is owned by the caller ofrdbuf().
ostream *ios::tie():This member function returns a pointer to theostreamobject that is currently tied to theiosobject (see the next member). The returnedostreamobject is flushed every time before information is input or output to theiosobject of which thetie()member is called. The return value 0 indicates that currently noostreamobject is tied to theiosobject. See section 5.8.2 for details.
ostream *ios::tie(ostream *new):
This member function can be used to associate aniosobject with anotherostreamobject. A pointer to theiosobject's originalostreamobject is returned. See section 5.8.2 for details.
Conditions are represented by the following condition flags:
ios::badbit:
if this flag has been raised an illegal operation has been
requested at the level of the streambuf object to which the stream
interfaces. See the member functions below for some examples.
ios::eofbit:
if this flag has been raised, the ios object has sensed
end of file.
ios::failbit:
if this flag has been raised, an operation performed by the
stream object has failed (like an attempt to extract an int when no
numeric characters are available on input). In this case the stream itself
could not perform the operation that was requested of it.
ios::goodbit:
this flag is raised when none of the other three condition flags were raised.
Several
condition member functions are available to manipulate or
determine the states of ios objects. Originally they returned int
values, but their current return type is bool:
ios::bad():
this member function returnstruewhenios::badbithas been set andfalseotherwise. Iftrueis returned it indicates that an illegal operation has been requested at the level of thestreambufobject to which the stream interfaces. What does this mean? It indicates that thestreambufitself is behaving unexpectedly. Consider the following example:std::ostream error(0);This constructs anostreamobject without providing it with a workingstreambufobject. Since this `streambuf' will never operate properly, itsios::badbitis raised from the very beginning:error.bad()returnstrue.
ios::eof():
this member function returnstruewhen end of file (EOF) has been sensed (i.e.,ios::eofbithas been set) andfalseotherwise. Assume we're reading lines line-by-line fromcin, but the last line is not terminated by a final\ncharacter. In that casegetline()attempting to read the\ndelimiter hits end-of-file first. This setseos::eofbit, andcin.eof()returnstrue. For example, assumemain()executes the statements:getline(cin, str); cout << cin.eof();Following:echo "hello world" | programthe value 0 (no EOF sensed) is printed, following:echo -n "hello world" | programthe value 1 (EOF sensed) is printed.
ios::fail():
this member function returnstruewhen ios::bad() returnstrueor when the ios::failbit was set, andfalseotherwise. In the above example,cin.fail()returnsfalse, whether we terminate the final line with a delimiter or not (as we've read a line). However, trying to execute a secondgetline()statement will setios::failbit, causingcin::fail()to returntrue. More in general:fail()returnstrueif the requested stream operation failed. A simple example consists of an attempt to extract anintwhen the input stream contains the texthello world. The valuenot fail()is returned by theboolinterpretation of a stream object (see below).
ios::good():
this member function returns the value of theios::goodbitflag. It returnstruewhen none of the other condition flags (ios::badbit, ios::eofbit, ios::failbit) were raised. Consider the following little program:#include <iostream> #include <string> using namespace std; void state() { cout << "\n" "Bad: " << cin.bad() << " " "Fail: " << cin.fail() << " " "Eof: " << cin.eof() << " " "Good: " << cin.good() << endl; } int main() { string line; int x; cin >> x; state(); cin.clear(); getline(cin, line); state(); getline(cin, line); state(); }When this program processes a file having two lines, containing, respectively,helloandworld, while the second line is not terminated by a\ncharacter it shows the following results:Bad: 0 Fail: 1 Eof: 0 Good: 0 Bad: 0 Fail: 0 Eof: 0 Good: 1 Bad: 0 Fail: 0 Eof: 1 Good: 0So, extractingxfails (good()returningfalse). Then, the error state is cleared, and the first line is successfully read (good()returningtrue). Finally the second line is read (incompletely):good()returnsfalse, andeof()returnstrue.
bool values:
streams may be used in expressions expecting logical values. Some examples are:if (cin) // cin itself interpreted as bool if (cin >> x) // cin interpreted as bool after an extraction if (getline(cin, str)) // getline returning cinWhen interpreting a stream as a logicalvalue, it is actually `not ios::fail()' that is interpreted. So, the above examples may be rewritten as:if (not cin.fail()) if (not (cin >> x).fail()) if (not getline(cin, str).fail())The former incantation, however, is used almost exclusively.
The following members are available to manage error states:
ios::clear():
When an error condition has occurred, and the condition can be repaired, thenclear()can be called to clear the error status of the file. An overloaded version accepts state flags, which are set after first clearing the current set of flags:ios::clear(int state). It's return type isvoid
ios::rdstate():
This member function returns (as anint) the current set of flags that are set for aniosobject. To test for a particular flag, use the bitwise and operator:if (iosObject.rdstate() & ios::good) { // state is good }
ios::setstate(int flags):
This member is used to set a particular set of flags. Its return type isvoid. The memberios::clear()is a shortcut to clear all error flags. Of course, clearing the flags doesn't automatically mean the error condition has been cleared too. The strategy should be:
- An error condition is detected,
- The error is repaired
- The member
ios::clear()is called.
Formatting is used when it is necessary to control the width of an output
field or an input buffer and if formatting is used to determine the form
(e.g., the
radix) in which a value is displayed. Most formatting belongs
to the realm of the ios class, although most formatting is actually used
with output streams, like the upcoming ostream class. Since the formatting
is controlled by flags, defined in the ios class, it was
considered best to discuss formatting with the ios class itself, rather
than with a selected derived class, where the choice of the derived class
would always be somewhat arbitrarily.
Formatting is controlled by a set of
formatting flags. These flags can
basically be altered in two ways: using specialized member functions,
discussed in section 5.3.2.2 or using manipulators, which are
directly inserted into streams. Manipulators are not applied directly to the
ios class, as they require the use of the insertion operator. Consequently
they are discussed later (in section 5.6).
int value is written as a set of
four bytes. Alternatively,
formatted output will convert the values that
are stored in bytes in the computer's memory to
ASCII-characters, in order
to create a human-readable form.
Formatting flags can be used to define the way this conversion takes place, to control, e.g., the number of characters that are written to the output stream.
The following formatting flags are available (see also sections 5.3.2.2 and 5.6):
ios::adjustfield:
mask value used in combination with a flag setting defining the way values are adjusted in wide fields (ios::left,ios::right,ios::internal). Example, setting the value 10 left-aligned in a field of 10 character positions:cout.setf(ios::left, ios::adjustfield); cout << "'" << setw(10) << 10 << "'" << endl;
ios::basefield:
mask value used in combination with a flag setting the radix of integral values to output (ios::dec,ios::hexorios::oct). Example, printing the value 57005 as a hexadecimal number:cout.setf(ios::hex, ios::basefield); cout << 57005 << endl; // or using the manipulator: cout << hex << 57005 << endl;
ios::boolalpha:
to display boolean values as text using the text `true' for thetruelogicalvalue, and the string `false' for thefalselogicalvalue. By default this flag is not set. Corresponding manipulators:boolalphaandnoboolalpha. Example, printing the boolean value `true' instead of 1:cout << boolalpha << (1 == 1) << endl;
ios::dec:
to read and display integral values as decimal (i.e., radix 10) values. This is the default. Withsetf()the mask valueios::basefieldmust be provided. Corresponding manipulator:dec.
ios::fixed:
to display real values in a fixed notation (e.g., 12.25), as opposed to displaying values in a scientific notation. If just a change of notation is requested the mask valueios::floatfieldmust be provided whensetf()is used. Example: seeios::scientificbelow. Corresponding manipulator:fixed.Another use of
ios::fixedis to set a fixed number of digits behind the decimal point when floating or double values are to be printed. Seeios::precisionin section 5.3.2.2.
ios::floatfield:
mask value used in combination with a flag setting the way real numbers are displayed (ios::fixedorios::scientific). Example:cout.setf(ios::fixed, ios::floatfield);
ios::hex:
to read and display integral values as hexadecimal values (i.e., radix 16) values. Withsetf()the mask valueios::basefieldmust be provided. Corresponding manipulator:hex.
ios::internal:
to add fill characters (blanks by default) between the minus sign of negative numbers and the value itself. Withsetf()the mask valueadjustfieldmust be provided. Corresponding manipulator:internal.
ios::left:
to left-adjust (integral) values in fields that are wider than needed to display the values. By default values are right-adjusted (see below). Withsetf()the mask valueadjustfieldmust be provided. Corresponding manipulator:left.
ios::oct:
to display integral values as octal values (i.e., radix 8) values. Withsetf()the mask valueios::basefieldmust be provided. Corresponding manipulator:oct.
ios::right:
to right-adjust (integral) values in fields that are wider than needed to display the values. This is the default adjustment. Withsetf()the mask valueadjustfieldmust be provided. Corresponding manipulator:right.
ios::scientific:
to display real values in scientific notation (e.g., 1.24e+03). Withsetf()the mask valueios::floatfieldmust be provided. Corresponding manipulator:scientific.
ios::showbase:
to display the numeric base of integral values. With hexadecimal values the0xprefix is used, with octal values the prefix0. For the (default) decimal value no particular prefix is used. Corresponding manipulators:showbaseandnoshowbase
ios::showpoint:
display a trailing decimal point and trailing decimal zeros when real numbers are displayed. When this flag is set, an insertion like:cout << 16.0 << ", " << 16.1 << ", " << 16 << endl;could result in:16.0000, 16.1000, 16Note that the last16is an integral rather than a real number, and is not given a decimal point:ios::showpointhas no effect here. Ifios::showpointis not used, then trailing zeros are discarded. If the decimal part is zero, then the decimal point is discarded as well. Corresponding manipulator:showpoint.
ios::showpos:
display a+character with positive values. Corresponding manipulator:showpos.
ios::skipws:
used for extracting information from streams. When this flag is set (which is the default) leading white space characters (blanks, tabs, newlines, etc.) are skipped when a value is extracted from a stream. If the flag is not set, leading white space characters are not skipped.
ios::unitbuf:
flush the stream after each output operation.
ios::uppercase:
use capital letters in the representation of (hexadecimal or scientifically formatted) values.
ios ©fmt(ios &obj):This member function copies all format definitions fromobjto the currentiosobject. The currentiosobject is returned.
ios::fill() const:returns (as char) the
current padding character. By default, this is the blank space.
ios::fill(char padding):
redefines the padding character. Returns (aschar) the previous padding character. Corresponding manipulator:setfill().
ios::flags() const:
returns the current collection of flags controlling the
format state of the stream for which the member function is called. To inspect
a particular flag, use the
binary and operator, e.g.,
if (cout.flags() & ios::hex)
{
// hexadecimal output of integral values
}
ios::flags(fmtflags flagset):
returns the previous set of flags, and defines the current set of flags asflagset, defined by a combination of formatting flags, combined by the binary or operator. Note: when setting flags using this member, a previously set flag may have to be unset first. For example, to change the number conversion ofcoutfrom decimal to hexadecimal using this member, do:cout.flags(ios::hex | cout.flags() & ~ios::dec);Alternatively, either of the following statements could have been used:cout.setf(ios::hex, ios::basefield); cout << hex;
ios::precision() const:
returns (as int) the number of
significant digits
used for outputting real values (default: 6).
ios::precision(int signif):
redefines the number of significant digits used for outputting real values, returns (asint) the previously used number of significant digits. Corresponding manipulator:setprecision(). Example, rounding all displayed double values to a fixed number of digits (e.g., 3) behind the decimal point:cout.setf(ios::fixed); cout.precision(3); cout << 3.0 << " " << 3.01 << " " << 3.001 << endl; cout << 3.0004 << " " << 3.0005 << " " << 3.0006 << endl;Note that the value 3.0005 is rounded away from zero to 3.001 (-3.0005 is rounded to -3.001).
ios::setf(fmtflags flags):
returns the previous set of all flags, and sets one or more formatting flags (using the bitwiseoperator|()to combine multiple flags. Other flags are not affected). Corresponding manipulators:setiosflagsandresetiosflags
ios::setf(fmtflags flags, fmtflags mask):
returns the previous set of all flags, clears all flags mentioned inmask, and sets the flags specified inflags. Well-known mask values areios::adjustfield,ios::basefieldandios::floatfield. For example:
setf(ios::left, ios::adjustfield)is used to left-adjust wide values in their field. (alternatively,ios::rightandios::internalcan be used).setf(ios::hex, ios::basefield)is used to activate the hexadecimal representation of integral values (alternatively,ios::decandios::octcan be used).setf(ios::fixed, ios::floatfield)is used to activate the fixed value representation of real values (alternatively,ios::scientificcan be used).
ios::unsetf(fmtflags flags):
returns the previous set of all flags, and clears
the specified formatting flags (leaving the remaining flags unaltered). The
unsetting of an active default flag (e.g., cout.unsetf(ios::dec)) has
no effect.
ios::width() const:returns (asint) the current output field width (the number of characters to write for numeric values on the next insertion operation). Default: 0, meaning `as many characters as needed to write the value'. Corresponding manipulator:setw().
ios::width(int nchars):
returns (asint) the previously used output field width, redefines the value toncharsfor the next insertion operation. Note that the field width is reset to 0 after every insertion operation, and thatwidth()currently has no effect on text-values likechar *orstringvalues. Corresponding manipulator:setw(int).
ostream class. The
ostream class defines the basic operators and members for inserting
information into streams: the
insertion operator (<<), and
special members like ostream::write() for writing unformatted information
to streams.
From the class ostream several other classes are derived, all having the
functionality of the ostream class, and adding their own specialties. In
the next sections on `output' we will introduce:
ostream, offering the basic facilities for doing output;
ofstream, allowing us to open files for writing
(comparable to C's
fopen(filename, "w"));
ostringstream, allowing us to write information to
memory rather than to files (streams) (comparable to C's
sprintf()
function).
ostream is the class defining basic output facilities. The
cout,
clog and
cerr objects are all ostream objects. Note that
all facilities defined in the ios class, as far as output is concerned, is
available in the ostream class as well, due to the inheritance mechanism
(discussed in chapter 13).
We can construct ostream objects using the following
ostream constructor:
ostream object(streambuf *sb):
this constructor can be used to construct a wrapper around
an existing streambuf, which may be the interface to an existing file. See
chapter 21 for examples. What this boils down to is that it isn't
possible to construct a plain ostream object that can be used for
insertions. When cout or its friends are used, we are actually using a
predefined ostream object that has already been created for us, and
interfaces to, e.g., the standard output stream using a (also predefined)
streambuf object handling the actual interfacing.
Note that it is possible to construct an ostream object passing it
a
0-pointer as a
streambuf. Such an object cannot be used for insertions (i.e., it will
raise its ios::bad flag when something is inserted into it), but since it
may be given a streambuf later, it may be preliminary constructed,
receiving its streambuf once it becomes available.
ostream class in C++ sources, the
#include <ostream>
preprocessor directive must be given. To use the
predefined ostream objects, the
#include <iostream> preprocessor
directive must be given.
ostream supports both formatted and
binary output.
The
insertion operator (<<) may be used to insert values in
a
type safe way into ostream objects. This is called
formatted output, as binary values which are stored in the computer's
memory are converted to human-readable
ASCII characters according to
certain formatting rules.
Note that the insertion operator points to the ostream object wherein the
information must be inserted. The normal associativity of <<
remains unaltered, so when a statement like
cout << "hello " << "world";
is encountered, the leftmost two operands are evaluated first (cout
<< "hello "), and an ostream & object, which is actually the
same cout object, is returned. Now, the statement is reduced to
cout << "world";
and the second string is inserted into cout.
The << operator has a lot of (overloaded) variants, so many types of
variables can be inserted into ostream objects. There is an overloaded
<<-operator expecting an int, a double, a pointer, etc. etc..
For every part of the information that is inserted into the stream the operator
returns the ostream object into which the information so far was inserted,
and the next part of the information to be inserted is processed.
Streams do not have facilities for formatted output like C's
printf() and
vprintf() functions. Although it is not difficult to
implement these facilities in the world of streams, printf()-like
functionality is hardly ever required in C++ programs. Furthermore, as it
is potentially type-unsafe, it might be better to avoid this functionality
completely.
When
binary files must be written, normally no
text-formatting is used or required: an int value should be written as a
series of unaltered bytes, not as a series of
ASCII numeric characters 0 to
9. The following member functions of ostream objects may be used to
write `binary files':
ostream& ostream::put(char c):
This member function writes a single character to the output stream. Since a character is a byte, this member function could also be used for writing a single character to a text-file.
ostream& ostream::write(char const *buffer, int length):
This member function writes at mostlenbytes, stored in thechar const *bufferto theostreamobject. The bytes are written as they are stored in the buffer, no formatting is done whatsoever. Note that the first argument is achar const *: a type_cast is required to write any other type. For example, to write anintas an unformatted series of byte-values:int x; out.write(reinterpret_cast<char const *>(&x), sizeof(int));
ostream object supports
repositioning, they usually
do. This means that it is possible to rewrite a section of the stream which
was written earlier. Repositioning is frequently used in
database applications where it must be possible to access the
information in the database randomly.
The following members are available:
pos_type ostream::tellp():
this function returns the current (absolute) position where the next write-operation to the stream will take place. For all practical purposes apos_typecan be considered to be anunsigned long.
ostream &ostream::seekp(off_type step, ios::seekdir org):
This member function can be used to reposition the stream. The function expects anoff_typestep, the stepsize in bytes to go fromorg. For all practical purposes anoff_typecan be considered to be along. The origin of the step,orgis anios::seekdirvalue. Possible values are:It is OK to seek beyond end of file . Writing bytes to a location beyond
ios::beg:orgis interpreted as the stepsize relative to the beginning of the stream. Iforgis not specified,ios::begis used.ios::cur:orgis interpreted as the stepsize relative to the current position (as returned bytellp()of the stream).ios::end:orgis interpreted as the stepsize relative to the current end position of the the stream.EOFwill pad the intermediate bytes with ASCII-Z values: null-bytes. It is not allowed to seek before the begining of a file. Seeking beforeios::begwill cause theios::failflag to be set.
ios::unitbuf flag has been set, information written to an
ostream object is not immediately written to the physical stream. Rather,
an internal buffer is filled up during the write-operations, and when full it
is flushed.
The internal buffer can be flushed under program control:
ostream& ostream::flush():
this member function writes any buffered information to theostreamobject. The call toflush()is implied when:
ofstream class is derived from the ostream class: it has the same
capabilities as the ostream class, but can be used to
access files or
create files for writing.
In order to use the ofstream class in C++ sources, the
preprocessor directive
#include <fstream> must be given. After
including fstream
cin, cout etc. are
not automatically declared. If these latter objects are needed too, then
iostream should be included.
The following
constructors are available for
ofstream objects:
ofstream object:
This is the basic constructor. It creates anofstreamobject which may be associated with an actual file later, using theopen()member (see below).
ofstream object(char const *name, int mode):
This constructor can be used to associate anofstreamobject with the file namednameusing output modemode. The output mode is by defaultios::out. See section 5.4.2.1 for a complete overview of available output modes.In the following example an
ofstreamobject, associated with the newly created file/tmp/scratch, is constructed:ofstream out("/tmp/scratch");
ofstream using a
file descriptor. The reason for this is (apparently) that file
descriptors are not universally available over different operating systems.
Fortunately, file descriptors can be used (indirectly) with a
streambuf
object (and in some implementations: with a
filebuf object, which is also
a streambuf). Streambuf objects are discussed in section
5.7, filebuf objects are discussed in section 5.7.2.
Instead of directly associating an ofstream object with a file, the
object can be constructed first, and opened later.
void ofstream::open(char const *name, int mode):Having constructed anofstreamobject, the member functionopen()can be used to associate theofstreamobject with an actual file.
ofstream::close():
Conversely, it is possible to close anofstreamobject explicitly using theclose()member function. The function sets theios::failflag of the closed object. Closing the file will flush any buffered information to the associated file. A file is automatically closed when the associatedofstreamobject ceases to exist.
ofstream ostr was
executed. When we now check its status through good(), a non-zero (i.e.,
OK) value will be returned. The `good' status here indicates that the
stream object has been properly constructed. It doesn't mean the file is also
open. To test whether a stream is actually open,
inspect
ofstream::is_open(): If
true, the stream is
open. See the following example:
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ofstream of;
cout << "of's open state: " << boolalpha << of.is_open() << endl;
of.open("/dev/null"); // on Unix systems
cout << "of's open state: " << of.is_open() << endl;
}
/*
Generated output:
of's open state: false
of's open state: true
*/
ofstream (or istream, see section 5.5.2) objects. The
values are of type
ios::openmode:
ios::app:
reposition to the end of the file before every output command. The existing contents of the file are kept.
ios::ate:
Start initially at the end of the file. The existing contents of the file are kept.
Note that the original contents are only kept if some other flag tells the object to do so. For exampleofstream out("gone", ios::ate)will rewrite the filegone, because the impliedios::outwill cause the rewriting. If rewriting of an existing file should be prevented, theios::inmode should be specified too. Note that in this case the construction only succeeds if the file already exists.
ios::binary:
open a binary file (used on systems which make a distinction between text- and binary files, like MS-DOS or MS-Windows).
ios::in:
open the file for reading. The file must exist.
ios::out:
open the file. Create it if it doesn't yet exist. If it exists, the file is rewritten.
ios::trunc:
Start initially with an empty file. Any existing contents of the file are lost.
out | app: The file is created if non-existing,
information is always added to the end of the
stream;
out | trunc: The file is (re)created empty to be written;
in | out: The stream may be read and written. However, the
file must exist.
in | out | trunc: The stream may be read and written. It is
(re)created empty first.
stream facilities,
ostringstream objects can be used. These objects
are derived from ostream objects. The following constructors and members
are available:
ostringstream ostr(string const &s, ios::openmode mode):When using this constructor, the last or both arguments may be omitted. There is also a constructor requiring only anopenmodeparameter. Ifstring sis specified andopenmodeisios::ate, theostringstreamobject is initialized with thestring sand remaining insertions are appended to the contents of theostringstreamobject. Ifstring sis provided, it will not be altered, as any information inserted into the object is stored in dynamically allocated memory which is deleted when theostringstreamobject goes out of scope.
string ostringstream::str() const:
This member function will return the string that is stored
inside the ostringstream object.
ostringstream::str(string):
This member function will re-initialize the
ostringstream object with new initial contents.
stringstream class was available the class
ostrstream
was commonly used for doing output to memory. This latter class suffered from
the fact that, once its contents were retrieved using its str() member
function, these contents were `frozen', meaning that its dynamically allocated
memory was not released when the object went out of scope. Although this
situation could be prevented (using the ostrstream member call
freeze(0)), this implementation could easily lead to
memory leaks. The stringstream class does not suffer from these
risks. Therefore, the use of the class ostrstream is now deprecated in
favor of ostringstream.
The following example illustrates the use of the ostringstream class:
several values are inserted into the object. Then, the stored text is stored
in a string, whose length and contents are thereupon printed. Such
ostringstream objects are most often used for doing `type to string'
conversions, like converting int to string. Formatting commands
can be used with stringstreams as well, as they are available in
ostream objects.
Here is an
example showing the use of an ostringstream object:
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
using namespace std;
int main()
{
ostringstream ostr("hello ", ios::ate);
cout << ostr.str() << endl;
ostr.setf(ios::showbase);
ostr.setf(ios::hex, ios::basefield);
ostr << 12345;
cout << ostr.str() << endl;
ostr << " -- ";
ostr.unsetf(ios::hex);
ostr << 12;
cout << ostr.str() << endl;
}
/*
Output from this program:
hello
hello 0x3039
hello 0x3039 -- 12
*/
istream class. The
istream class defines the basic operators and members for extracting
information from streams: the
extraction operator (>>), and
special members like istream::read() for reading unformatted information
from streams.
From the class istream several other classes are derived, all having the
functionality of the istream class, and adding their own specialties. In
the next sections we will introduce:
istream, offering the basic facilities for doing input;
ifstream, allowing us to open files for reading
(comparable to C's
fopen(filename, "r"));
istringstream, allowing us to read information from
text that is not stored on files (streams) but in memory (comparable to
C's
sscanf() function).
istream is the I/O class defining basic input facilities. The
cin object is an istream object that is declared when sources contain
the
preprocessor directive
#include <iostream>. Note that
all facilities defined in the ios class are, as far as input is concerned,
available in the istream class as well due to the inheritance mechanism
(discussed in chapter 13).
Istream objects can be constructed using the following
istream constructor:
istream object(streambuf *sb):
this constructor can be used to construct a wrapper around an existing open stream, based on an existingstreambuf, which may be the interface to an existing file. Similarly toostreamobjects,istreamobjects may initially be constructed using a 0-pointer. See section 5.4.1 for a discussion, and chapter 21 for examples.
istream class in C++ sources, the
#include <istream>
preprocessor directive must be given. To use the
predefined istream object
cin, the
#include <iostream>
preprocessor directive must be given.
istream supports both formatted and unformatted
binary input. The
extraction operator (
operator>>()) may be
used to extract values in a
type safe way from istream objects. This
is called
formatted input, whereby human-readable
ASCII characters are
converted, according to certain formatting rules, to binary values which are
stored in the computer's memory.
Note that the extraction operator points to the objects or variables which must receive new values. The normal associativity of >> remains unaltered, so when a statement like
cin >> x >> y;
is encountered, the leftmost two
operands are evaluated first (cin >> x), and an istream &
object, which is actually the same cin object, is returned. Now, the
statement is reduced to
cin >> y
and the y variable is extracted from cin.
The >> operator has various (overloaded) variants and thus many types of
variables can be extracted from istream objects. There is an overloaded
>> available for the extraction of an int, of a double, of a
string, of an array of characters, possibly to a pointer, etc. etc.. String or
character array extraction
will
(by default) skip all white space characters, and will then extract all
consecutive non-white space characters. Once an extraction operator has been
processed the istream object from which the information was extracted is
returned and it can immediately be used for any subsequent istream
operations that follow in the same expression.
Streams do not have facilities for formatted input (like C's
scanf() and
vscanf() functions). Although it is not difficult to make
these facilities available in the world of streams, scanf()-like
functionality is hardly ever required in C++ programs. Furthermore, as it
is potentially type-unsafe, it might be better to avoid this functionality
completely.
When
binary files must be read, the information should
normally not be formatted: an int value should be read as a series of
unaltered bytes, not as a series of
ASCII numeric characters 0 to 9. The
following member functions for reading information from istream objects
are available:
int istream::gcount():
this function does not actually read from the input stream, but returns the number of characters that were read from the input stream during the last unformatted input operation.
int istream::get():
this function returnsEOFor reads and returns the next available single character as anintvalue.
istream &istream::get(char &c):
this function reads the next single character from the input
stream into c. As its return value is the stream itself, its return value
can be queried to determine whether the extraction succeeded or not.
istream& istream::get(char *buffer, int len [, char delim]):
This function reads a series oflen - 1characters from the input stream into the array starting atbuffer, which should be at leastlenbytes long. At mostlen - 1characters are read into the buffer. By default, the delimiter is a newline ('\n') character. The delimiter itself is not removed from the input stream.After reading the series of characters into
buffer, anASCII-Zcharacter is written beyond the last character that was written tobuffer. The functionseof()andfail()(see section 5.3.1) return 0 (false) if the delimiter was not encountered beforelen - 1characters were read. Furthermore, anASCII-Zcan be used for the delimiter: this way strings terminating inASCII-Zcharacters may be read from a (binary) file. The program using thisget()member function should know in advance the maximum number of characters that are going to be read.
istream& istream::getline(char *buffer, int len [, char delim]):
This function operates analogously to the previousget()member function, butdelimis removed from the stream if it is actually encountered. At mostlen - 1bytes are written into thebuffer, and a trailingASCII-Zcharacter is appended to the string that was read. The delimiter itself is not stored in thebuffer. Ifdelimwas not found (before readinglen - 1characters) thefail()member function, and possibly alsoeof()will return true. Note that thestd::stringclass also has a support functiongetline()which is used more often than thisistream::getline()member function (see section 4.2.4).
istream& istream::ignore(int n , int delim):
This member function has two (optional) arguments. When called without arguments, one character is skipped from the input stream. When called with one argument,ncharacters are skipped. The optional second argument specifies a delimiter: after skippingnor thedelimcharacter (whichever comes first) the function returns.
int istream::peek():
this function returns the next available input character, but does not actually remove the character from the input stream.
istream& istream::putback (char c):
The charactercthat was last read from the stream is `pushed back' into the input stream, to be read again as the next character.EOFis returned if this is not allowed. Normally, one character may always be put back. Note thatcmust be the character that was last read from the stream. Trying to put back any other character will fail.
istream& istream::read(char *buffer, int len):
This function reads at mostlenbytes from the input stream into the buffer. IfEOFis encountered first, fewer bytes are read, and the member functioneof()will returntrue. This function will normally be used for reading binary files. Section 5.5.2 contains an example in which this member function is used. The member functiongcount()should be used to determine the number of characters that were retrieved by theread()member function.
istream& istream::readsome(char *buffer, int len):
This function reads at mostlenbytes from the input stream into the buffer. All available characters are read into the buffer, but ifEOFis encountered first, fewer bytes are read, without setting theios_base::eofbitorios_base::failbit.
istream& istream::unget():
an attempt is made to push back the last character that was
read into the stream. Normally, this succeeds if requested only once after a
read operation, as is the case with putback()
istream object supports
repositioning, some do. This
means that it is possible to read the same section of a stream
repeatedly. Repositioning is frequently used in
database applications
where it must be possible to access the information in the database randomly.
The following members are available:
pos_type istream::tellg():
this function returns the current (absolute) position where the next read-operation to the stream will take place. For all practical purposes apos_typecan be considered to be anunsigned long.
istream &istream::seekg(off_type step, ios::seekdir org):This member function can be used to reposition the stream. The function expects anoff_typestep, the stepsize in bytes to go fromorg. For all practical purposes apos_typecan be considered to be along. The origin of the step,orgis aios::seekdirvalue. Possible values are:While it is OK to seek beyond end of file, reading at that point will of course fail. It is not allowed to seek before begin of file. Seeking before
ios::beg:stepis interpreted as the stepsize relative to the beginning of the stream. Iforgis not specified,ios::begis used.ios::cur:stepis interpreted as the stepsize relative to the current position (as returned bytellg()of the stream).ios::end:stepis interpreted as the stepsize relative to the current end position of the the stream.ios::begwill cause theios::failflag to be set.
ifstream is derived from the class istream: it has the same
capabilities as the istream class, but can be used to
access files for
reading. Such files must exist.
In order to use the ifstream class in C++ sources, the
preprocessor directive
#include <fstream> must be given.
The following
constructors are available for
ifstream objects:
ifstream object:
This is the basic constructor. It creates anifstreamobject which may be associated with an actual file later, using theopen()member (see below).
ifstream object(char const *name, int mode):
This constructor can be used to associate anifstreamobject with the file namednameusing input modemode. The input mode is by defaultios::in. See also section 5.4.2.1 for an overview of available file modes.In the following example an
ifstreamobject is opened for reading. The file must exist:ifstream in("/tmp/scratch");
ifstream object with a file, the
object can be constructed first, and opened later.
void ifstream::open(char const *name, int mode):
Having constructed anifstreamobject, the member functionopen()can be used to associate theifstreamobject with an actual file.
ifstream::close():
Conversely, it is possible to close anifstreamobject explicitly using theclose()member function. The function sets theios::failflag of the closed object. A file is automatically closed when the associatedifstreamobject ceases to exist.
ifstream ostr was
executed. When we now check its status through good(), true (i.e.,
OK) is returned. The `good' status here indicates that the
stream object has been properly constructed. It doesn't mean the file is also
open. To test whether a stream is actually open,
inspect
ifstream::is_open(): If
true, the stream is
open. See also the example in section 5.4.2.
To illustrate reading from a binary file (see also section 5.5.1.1),
a double value is read in binary form from a
file in the next example:
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
ifstream f(argv[1]);
double d;
// reads double in binary form.
f.read(reinterpret_cast<char *>(&d), sizeof(double));
}
stream facilities,
istringstream objects can be used. These objects
are derived from istream objects. The following constructors and members
are available:
istringstream istr:
The constructor will construct an empty istringstream
object. The object may be filled with information to be extracted later.
istringstream istr(string const &text):
The constructor will construct anistringstreamobject initialized with the contents of the stringtext.
void istringstream::str(string const &text):
This member function will store the contents of the stringtextinto theistringstreamobject, overwriting its current contents.
The istringstream object is commonly used for
converting ASCII text to its binary equivalent, like the C function
atoi(). The following example illustrates the use of the istringstream
class, note especially the use of the member
seekg():
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main()
{
istringstream istr("123 345"); // store some text.
int x;
istr.seekg(2); // skip "12"
istr >> x; // extract int
cout << x << endl; // write it out
istr.seekg(0); // retry from the beginning
istr >> x; // extract int
cout << x << endl; // write it out
istr.str("666"); // store another text
istr >> x; // extract it
cout << x << endl; // write it out
}
/*
output of this program:
3
123
666
*/
Ios objects define a set of format flags that are used for determining
the way values are inserted and extracted (see section 5.3.2.1). The
format flags can be controlled by member functions (see section
5.3.2.2), but also by
manipulators. Manipulators are
inserted into output streams or extracted from input streams, instead of
being activated through the member selection operator (`.').
Manipulators are functions. New manipulators can be constructed as well. The construction of manipulators is covered in section 9.10.1. In this section the manipulators that are available in the C++ I/O library are discussed. Most manipulators affect format flags. See section 5.3.2.1 for details about these flags. Most manipulators are parameterless. Sources in which manipulators expecting arguments are used, must do:
#include <iomanip>
std::boolalpha:
This manipulator will set the ios::boolalpha flag.
std::dec:
This manipulator enforces the display and reading of integral numbers in decimal format. This is the default conversion. The conversion is applied to values inserted into the stream after processing the manipulators. For example (see alsostd::hexandstd::oct, below):cout << 16 << ", " << hex << 16 << ", " << oct << 16; // produces the output: 16, 10, 20
std::endl:
This manipulator will insert a newline character into an output buffer and will flush the buffer thereafter.
std::ends:
This manipulator will insert a string termination character into an output buffer.
std::fixed:
This manipulator will set the ios::fixed flag.
std::flush:
This manipulator will flush an output buffer.
std::hex:
This manipulator enforces the display and reading of integral numbers in hexadecimal format.
std::internal:
This manipulator will set the ios::internal flag.
std::left:
This manipulator will align values to the left in wide fields.
std::noboolalpha:
This manipulator will clear the ios::boolalpha flag.
std::noshowpoint:
This manipulator will clear the ios::showpoint flag.
std::noshowpos:
This manipulator will clear the ios::showpos flag.
std::noshowbase:
This manipulator will clear the ios::showbase flag.
std::noskipws:
This manipulator will clear the ios::skipws flag.
std::nounitbuf:
This manipulator will stop flushing an output stream after each write operation. Now the stream is flushed at aflush,endl,unitbufor when it is closed.
std::nouppercase:
This manipulator will clear the ios::uppercase flag.
std::oct:
This manipulator enforces the display and reading of integral numbers in octal format.
std::resetiosflags(flags):This manipulator
calls std::resetf(flags) to clear the indicated flag values.
std::right:
This manipulator will align values to the right in wide fields.
std::scientific:
This manipulator will set the ios::scientific flag.
std::setbase(int b):
This manipulator can be used to display integral values using
the base 8, 10 or 16. It can be used as an alternative to oct, dec, hex in
situations where the base of integral values is parameterized.
std::setfill(int ch):
This manipulator defines the filling character in situations where the values of numbers are too small to fill the width that is used to display these values. By default the blank space is used.
std::setiosflags(flags):This manipulator calls
std::setf(flags) to set the indicated flag values.
std::setprecision(int width):
This manipulator will set the precision in which afloatordoubleis displayed. In combination withstd::fixedit can be used to display a fixed number of digits of the fractional part of a floating or double value:cout << fixed << setprecision(3) << 5.0 << endl; // displays: 5.000
std::setw(int width):
This manipulator expects as its argument the width of the field that is inserted or extracted next. It can be used as manipulator for insertion, where it defines the maximum number of characters that are displayed for the field, but it can also be used during extraction, where it defines the maximum number of characters that are inserted into an array of characters. To prevent array bounds overflow when extracting fromcin,setw()can be used as well:cin >> setw(sizeof(array)) >> array;A nice feature is that a long string appearing atcinis split into substrings of at mostsizeof(array) - 1characters, and that anASCII-Zcharacter is automatically appended.Notes:
setw()is valid only for the next field. It does not act like e.g.,hexwhich changes the general state of the output stream for displaying numbers.- When
setw(sizeof(someArray))is used, make sure thatsomeArrayreally is an array, and not a pointer to an array: the size of a pointer, being, e.g., four bytes, is usually not the size of the array that it points to....- The
ASCII-Zcharacter that is appended to the extracted string is counted insetw's argument. So specifysetw(3)to extract two characters.
std::showbase:
This manipulator will set the ios::showbase flag.
std::showpoint:
This manipulator will set the ios::showpoint flag.
std::showpos:
This manipulator will set the ios::showpos flag.
std::skipws:
This manipulator will set the ios::skipws flag.
std::unitbuf:
This manipulator will flush an output stream after each write operation.
std::uppercase:
This manipulator will set the ios::uppercase flag.
std::ws:
This manipulator will remove all whitespace characters that are available at the current read-position of an input buffer.
streambuf defines the input and output character sequences that
are processed by streams. Like an
ios object, a streambuf object is
not directly constructed, but is implied by objects of other classes that are
specializations of the class streambuf.
The class plays an important role in offering features that were
available as extensions to the pre-
ANSI/ISO standard implementations of
C++. Although the class cannot be used directly, its members are
introduced here, as the current chapter is the most logical place to introduce
the class streambuf. However, this section of the current chapter assumes
a basic familiarity with the concept of polymorphism, a topic discussed in
detail in chapter 14. Readers not yet familiar with the concept
of polymorphism may, for the time being, skip this section without loss of
continuity.
The primary reason for existence of the class streambuf, however, is
to decouple the stream classes from the
devices they operate
upon. The rationale here is to use an extra software layer between, on the one
hand, the classes allowing us to communicate with the device and, on the other
hand, the communication between the software and the devices themselves. This
implements a
chain of command which is seen regularly in
software design:
The chain of command is considered a generic pattern for the
construction of
reusable software, encountered also in, e.g., the
TCP/IP stack.
A streambuf can be considered yet another example of the chain of
command pattern: here the program talks to stream objects, which in turn
forward their requests to streambuf objects, which in turn communicate
with the devices. Thus, as we will see shortly, we are now able to do in
user-software what had to be done via (expensive) system calls before.
The class streambuf has no public constructor, but does make available
several public member functions. In addition to these public member functions,
several member functions are available to specializing classes only. These
protected members are listed in this section for further
reference. In section 5.7.2 below, a particular specialization of the
class streambuf is introduced. Note that all public members of
streambuf discussed here are also available in filebuf.
In section 14.6 the process of constructing specializations
of the class streambuf is discussed, and in chapter 21 several
other implications of using streambuf objects are mentioned. In the
current chapter examples of copying streams, of redirecting streams and and of
reading and writing to streams using the streambuf members of stream
objects are presented (section 5.8).
With the class streambuf the following public member functions are
available. The type
streamsize that is used below may, for all practical
purposes, be considered an unsigned int.
Public members for input operations:
streamsize streambuf::in_avail():This member function returns a lower bound on the number of characters that can be read immediately.
int streambuf::sbumpc():This member function returns the next available character orEOF. The returned character is removed from thestreambufobject. If no input is available,sbumpc()will call the (protected) memberuflow()(see section 5.7.1 below) to make new characters available.EOFis returned if no more characters are available.
int streambuf::sgetc():This member function returns the next available character orEOF. The character is not removed from thestreambufobject, however.
int streambuf::sgetn(char *buffer, streamsize n):This member function readsncharacters from the input buffer, and stores them inbuffer. The actual number of characters read is returned. This member function calls the (protected) memberxsgetn()(see section 5.7.1 below) to obtain the requested number of characters.
int streambuf::snextc():This member function removes the current character from the input buffer and returns the next available character orEOF. The character is not removed from thestreambufobject, however.
int streambuf::sputback(char c):Insertscas the next character to read from thestreambufobject. Caution should be exercised when using this function: often there is a maximum of just one character that can be put back.
int streambuf::sungetc():Returns the last character read to the input buffer, to be read again at the next input operation. Caution should be exercised when using this function: often there is a maximum of just one character that can be put back.
Public members for output operations:
int streambuf::pubsync():Synchronize (i.e., flush) the buffer, by writing any pending
information available in the streambuf's buffer to the
device. Normally used only by specializing classes.
int streambuf::sputc(char c):This member function insertscinto thestreambufobject. If, after writing the character, the buffer is full, the function calls the (protected) member functionoverflow()to flush the buffer to the device (see section 5.7.1 below).
int streambuf::sputn(char const *buffer, streamsize n):This member function insertsncharacters frombufferinto thestreambufobject. The actual number of inserted characters is returned. This member function calls the (protected) memberxsputn()(see section 5.7.1 below) to insert the requested number of characters.
Public members for miscellaneous operations:
pos_type streambuf::pubseekoff(off_type offset, ios::seekdir way,
ios::openmode mode = ios::in | ios::out):Reset the offset of the next character to be read or written tooffset, relative to the standardios::seekdirvalues indicating the direction of the seeking operation. Normally used only by specializing classes.
pos_type streambuf::pubseekpos(pos_type offset,
ios::openmode mode = ios::in | ios::out):Reset the
absolute position of the next character to be read or
written to pos. Normally used only by specializing classes.
streambuf *streambuf::pubsetbuf(char* buffer, streamsize n):Deploybufferas the buffer to be used by thestreambufobject. Normally used only by specializing classes.
class
streambuf are normally not
accessible. However, they are accessible in specializing classes which are
derived from streambuf. They are important for understanding and using
the class streambuf. Usually there are both protected
data members and
protected
member functions defined in the class streambuf. Since using
data members immediately violates the principle of
encapsulation, these
members are not mentioned here. As the functionality of streambuf, made
available via its member functions, is quite extensive, directly using its
data members is probably hardly ever necessary. This section does not even
list all protected member functions of the class streambuf. Only those
member functions are mentioned that are useful in constructing
specializations. The class streambuf maintains an input- and/or and output
buffer, for which begin-, actual- and end-pointers have been defined, as
depicted in figure 4. In upcoming sections we will refer to this
figure repeatedly.

Several protected member functions are related to
input operations. The
member functions marked as virtual may be redefined in classes derived
from streambuf. In those cases, the redefined function will be called by
i/ostream objects that received the addresses of such derived class
objects. See chapter 14 for details about virtual member
functions. Here are the protected members:
char *streambuf::eback():For the input buffer theclass streambufmaintains three pointers:eback()points to the `end of the putback' area: characters can safely be put back up to this position. See also figure 4.Eback()can be considered to represent the beginning of the input buffer.
char *streambuf::egptr():For the input buffer theclass streambufmaintains three pointers:egptr()points just beyond the last character that can be retrieved. See also figure 4. Ifgptr()(see below) equalsegptr()the buffer must be refilled. This should be implemented by callingunderflow(), see below.
void streambuf::gbump(int n):This function moves the input pointer over n positions.
char *streambuf::gptr():For the input buffer theclass streambufmaintains three pointers:gptr()points to the next character to be retrieved. See also figure 4.
virtual int streambuf::pbackfail(int c):This member function may be redefined by specializations of theclass streambufto do something intelligent when putting back charactercfails. One of the things to consider here is to restore the old read pointer when putting back a character fails, because the beginning of the input buffer is reached. This member function is called when ungetting or putting back a character fails.
void streambuf::setg(char *beg, char *next, char *beyond):This member function initializes an input buffer:begpoints to the beginning of the input area,nextpoints to the next character to be retrieved, andbeyondpoints beyond the last character of the input buffer. Ususallynextis at leastbeg + 1, to allow for a put back operation. No input buffering is used when this member is called with 0-arguments (not no arguments, but arguments having 0 values.) See also the memberstreambuf::uflow(), below.
virtual streamsize streambuf::showmanyc():(Pronounce: s-how-many-c) This member function may be redefined by specializations of theclass streambuf. It must return a guaranteed lower bound on the number of characters that can be read from the device beforeuflow()orunderflow()returnsEOF. By default 0 is returned (meaning at least 0 characters will be returned before the latter two functions will returnEOF).
virtual int streambuf::uflow():This member function may be redefined by specializations of theclass streambufto reload an input buffer with new characters. The default implementation is to callunderflow(), see below, and to increment the read pointergptr(). When no input buffering is required this function, rather thanunderflow()can be overridden to produce the next available character from the device to read.
virtual int streambuf::underflow():This member function may be redefined by specializations of theclass streambufto read another character from the device. The default implementation is to returnEOF. When buffering is used, often the complete buffer is not refreshed, as this would make it impossible to put back characters just after a reload. This system, where only a subsection of the input buffer is reloaded, is called a split buffer.
virtual streamsize streambuf::xsgetn(char *buffer, streamsize n):This member function may be redefined by specializations of theclass streambufto retrievencharacters from the device. The default implementation is to callsbumpc()for every single character. By default this calls (eventually)underflow()for every single character.
Here are the protected member functions related to
output
operations. Similarly to the functions related to input operations, some of
the following functions are virtual: they may be redefined in derived
classes:
virtual int streambuf::overflow(int c):This member function may be redefined by specializations of theclass streambufto flush the characters in the output buffer to the device, and then to reset the output buffer pointers such that the buffer may be considered empty. It receives as parametercthe next character to be processed by thestreambuf. If no output buffering is used,overflow()is called for every single character which is written to thestreambufobject. This is implemented by setting the buffer pointers (using, e.g.,setp(), see below) to 0. The default implementation returnsEOF, indicating that no characters can be written to the device.
char *streambuf::pbase():For the output buffer theclass streambufmaintains three pointers:pbase()points to the beginning of the output buffer area. See also figure 4.
char *streambuf::epptr():For the output buffer theclass streambufmaintains three pointers:epptr()points just beyond the location of the last character that can be written. See also figure 4. Ifpptr()(see below) equalsepptr()the buffer must be flushed. This is implemented by callingoverflow(), see earlier.
void streambuf::pbump(int n):This function moves the output pointer over n positions.
char *streambuf::pptr():For the output buffer theclass streambufmaintains three pointers:pptr()points to the location of the next character to be written. See also figure 4.
void streambuf::setp(char *beg, char *beyond):This member function initializes an output buffer:begpoints to the beginning of the output area andbeyondpoints beyond the last character of the output area. Use 0 for the arguments to indicate that no buffering is requested. In that caseoverflow()is called for every single character to write to the device.
streamsize streambuf::xsputn(char const *buffer, streamsize n):This member function may be redefined by specializations of theclass streambufto writencharacters immediately to the device. The actual number of inserted characters should be returned. The default implementation callssputc()for each individual character, so redefining is only needed if a more efficient implementation is required.
Protected member functions related to buffer management and positioning:
virtual streambuf *streambuf::setbuf(char *buffer, streamsize n):This member function may be redefined by specializations of the
class streambuf to install a buffer. The default implementation is
to do nothing.
virtual
pos_type streambuf::seekoff(off_type offset,
ios::seekdir way,ios::openmode mode = ios::in | ios::out)
This member function may be redefined by specializations of theclass streambufto reset the next pointer for input or output to a new relative position (usingios::beg, ios::curorios::end). The default implementation is to indicate failure by returning -1. The function is called when, e.g.,tellg()ortellp()is called. When astreambufspecialization supports seeking, then the specialization should also define this function to determine what to do with a repositioning request.
virtual pos_type streambuf::seekpos(pos_type offset,
ios::openmode mode =ios::in | ios::out):
This member function may be redefined by specializations of theclass streambufto reset the next pointer for input or output to a new absolute position (i.e, relative toios::beg). The default implementation is to indicate failure by returning -1.
virtual int sync():This member function may be redefined by specializations of theclass streambufto flush the output buffer to the device or to reset the input device to the position of the last consumed character. The default implementation (not using a buffer) is to return 0, indicating successful syncing. The member function is used to make sure that any characters that are still buffered are written to the device or to restore unconsumed characters to the device when thestreambufobject ceases to exist.
class streambuf are designed,
the very least thing to do is to redefine underflow() for specializations
aimed at reading information from devices, and to redefine overflow() for
specializations aimed at writing information to devices. Several examples of
specializations of the class streambuf will be given in the C++
Annotations (e.g., in chapter 21).
Objects of the class fstream use a combined input/output buffer. This
results from the fact that istream and ostream, are virtually derived
from ios, which contains the streambuf. As explained in section
14.4.2, this implies that classes derived from both istream and
ostream share their streambuf pointer. In order to construct a class
supporting both input and output on separate buffers, the streambuf itself
may define internally two buffers. When seekoff() is called for reading,
its mode parameter is set to ios::in, otherwise to ios::out. This
way, the streambuf specializaiton knows whether it should access the
read buffer or the write buffer. Of course, underflow() and
overflow() themselves already know on which buffer they should operate.
class
filebuf is a specialization of
streambuf used by the
file
stream classes. Apart from the (public) members that are available
through the class streambuf, it defines the following extra (public)
members:
filebuf::filebuf():Since the class has a constructor, it is, different from theclass streambuf, possible to construct afilebufobject. This defines a plainfilebufobject, not yet connected to a stream.
bool filebuf::is_open():This member function returnstrueif thefilebufis actually connected to an open file. See theopen()member, below.
filebuf *filebuf::open(char const *name, ios::openmode mode):This member function associates thefilebufobject with a file whose name is provided. The file is opened according to the providedios::openmode.
filebuf *filebuf::close():This member function closes the association between thefilebufobject and its file. The association is automatically closed when thefilebufobject ceases to exist.
filebuf objects can be defined the following preprocessor
directive must have been specified:
#include <fstream>
fail() returns
true), break from the loop
getline(istream &, string &) (see section 5.5.1.1) returns an
istream & itself, so here reading and testing may be implemented in one
expression. Nevertheless, the above mold represents the general case. So,
the following program could be used to copy cin to cout:
#include <iostream>
using namespace::std;
int main()
{
while (true)
{
char c;
cin.get(c);
if (cin.fail())
break;
cout << c;
}
return 0;
}
By combining the get() with the if-statement a construction
comparable to getline() could be used:
if (!cin.get(c))
break;
Note, however, that this would still follow the basic rule:
`
read first, test later'.
This simple copying of a file, however, isn't required very often. More
often, a situation is encountered where a file is processed up to a certain
point, whereafter the remainder of the file can be copied unaltered. The
following program illustrates this situation: the ignore() call is used to
skip the first line (for the sake of the example it is assumed that the first
line is at most 80 characters long), the second statement uses a special
overloaded version of the <<-operator, in which a
streambuf pointer
is inserted into another stream. As the member
rdbuf() returns a streambuf *, it can thereupon be inserted into
cout. This immediately copies the remainder of cin to cout:
#include <iostream>
using namespace std;
int main()
{
cin.ignore(80, '\n'); // skip the first line
cout << cin.rdbuf(); // copy the rest by inserting a streambuf *
}
Note that this method assumes a streambuf object, so it will work for
all specializations of streambuf. Consequently, if the class streambuf
is specialized for a particular
device it can be inserted into any other
stream using the above method.
ios objects using the
tie() member function. This results in flushing all buffered output of the
ostream object (by calling flush()) whenever an
input or
output
operation is performed on the ios object to which the ostream object
is tied. By default
cout is tied to
cin (i.e., cin.tie(cout)):
whenever an operation on cin is requested, cout is flushed first. To
break the coupling, the member function ios::tie(0) can be called.
Another (frequently useful, but non-default) example of coupling streams is to
tie
cerr to
cout: this way standard output and error messages written
to the screen will appear in sync with the time at which they were generated:
#include <iostream>
using namespace std;
int main()
{
cout << "first (buffered) line to cout ";
cerr << "first (unbuffered) line to cerr\n";
cout << "\n";
cerr.tie(&cout);
cout << "second (buffered) line to cout ";
cerr << "second (unbuffered) line to cerr\n";
cout << "\n";
}
/*
Generated output:
first (buffered) line to cout
first (unbuffered) line to cerr
second (buffered) line to cout second (unbuffered) line to cerr
*/
An alternative way to couple streams is to make streams use a common
streambuf object. This can be implemented using the
ios::rdbuf(streambuf *) member function. This way two streams can use,
e.g. their own formatting, one stream can be used for input, the other for
output, and redirection using the iostream library rather than operating
system calls can be implemented. See the next sections for examples.
ios::rdbuf() member streams can share their streambuf
objects. This means that the information that is written to a stream will
actually be written to another stream, a phenomenon normally called
redirection. Redirection is normally implemented at the level of the
operating system, and in some situations that is still necessary (see section
21.4.1).
A standard situation where redirection is wanted is to write error messages to
file rather than to standard error, usually indicated by its
file descriptor number 2. In the
Unix operating system using the
bash shell, this can be implemented as follows:
program 2>/tmp/error.log
With this command any error messages written by program will be saved
on the file /tmp/error.log, rather than being written to the screen.
Here is how this can be implemented using streambuf objects. Assume
program now expects an optional argument defining the name of the file to
write the error messages to; so program is now called as:
program /tmp/error.log
Here is the example implementing redirection. It is annotated below.
#include <iostream>
#include <streambuf>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
ofstream errlog; // 1
streambuf *cerr_buffer = 0; // 2
if (argc == 2)
{
errlog.open(argv[1]); // 3
cerr_buffer = cerr.rdbuf(errlog.rdbuf()); // 4
}
else
{
cerr << "Missing log filename\n";
return 1;
}
cerr << "Several messages to stderr, msg 1\n";
cerr << "Several messages to stderr, msg 2\n";
cout << "Now inspect the contents of " <<
argv[1] << "... [Enter] ";
cin.get(); // 5
cerr << "Several messages to stderr, msg 3\n";
cerr.rdbuf(cerr_buffer); // 6
cerr << "Done\n"; // 7
}
/*
Generated output on file argv[1]
at cin.get():
Several messages to stderr, msg 1
Several messages to stderr, msg 2
at the end of the program:
Several messages to stderr, msg 1
Several messages to stderr, msg 2
Several messages to stderr, msg 3
*/
errlog is the
ofstream to write the error messages too, and cerr_buffer is a pointer
to a streambuf, to point to the original cerr buffer. This is further
discussed below.
cerr will now write to
the streambuf defined by errlog. It is important that
the original buffer used by cerr is saved, as explained below.
errlog object is destroyed at the end of main(). If cerr's
buffer would not have been restored, then at that point
cerr would refer to a non-existing streambuf object, which might
produce unexpected results. It is the
responsibility of the programmer to
make sure that an original streambuf is saved before redirection, and is
restored when the redirection ends.
Done is now written to the screen again, as
the redirection has been terminated.
fstream object
must be created. As with ifstream and ofstream objects, its
constructor receives the name of the file to be opened:
fstream inout("iofile", ios::in | ios::out);
Note the use of the
ios constants
ios::in and
ios::out,
indicating that the file must be opened for both reading and writing. Multiple
mode indicators may be used, concatenated by the binary or operator '|'.
Alternatively, instead of ios::out,
ios::app could have been used, in
which case writing will always be done at the end of the file.
Somehow reading and writing to a file is a bit awkward: what to do when the file may or may not exist yet, but if it already exists it should not be rewritten? I have been fighting with this problem for some time, and now I use the following approach:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
fstream rw("fname", ios::out | ios::in);
if (!rw)
{
rw.clear();
rw.open("fname", ios::out | ios::trunc | ios::in);
}
if (!rw)
{
cerr << "Opening `fname' failed miserably" << endl;
return 1;
}
cerr << rw.tellp() << endl;
rw << "Hello world" << endl;
rw.seekg(0);
string s;
getline(rw, s);
cout << "Read: " << s << endl;
}
In the above example, the constructor fails when fname doesn't exist
yet. However, in that case the open() member will normally succeed since
the file is created due to the ios::trunc flag. If the file already
existed, the constructor will succeed. If the
ios::ate flag would have
been specified as well with rw's initial construction, the first
read/write action would by default have take place at EOF. However,
ios::ate is not
ios::app, so it would then still have been possible to
repositioned rw using seekg() or seekp().
Under
DOS-like operating
systems, using the multiple character \r\n sentinels to separate lines in
text files the flag
ios::binary is required for processing
binary files
to ensure that \r\n combinations are processed as two
characters. In general, ios::binary should be usd when binary (non-text)
files are to be processed. Text files are assumed when ios::binary is not
specified. This will leave the proper handling of line-endings to the run-time
support system.
With fstream objects, combinations of file flags are used to make sure
that a stream is or is not (re)created empty when opened. See section
5.4.2.1 for details.
Once a file has been opened in read and write mode, the << operator
can be used to insert information into the file, while the >> operator
may be used to extract information from the file. These operations may be
performed in any order, but a seekg() or seekp() operation is required
when switching between insertions and extractions. The following fragment
will read a blank-delimited word from the file, and will then write a string
to the file, just beyond the point where the string just read terminated,
followed by the reading of yet another string just beyond the location where
the string just written ended (assuming that the file filename contains
enough information for the extractions to succeed):
fstream f("filename", ios::in | ios::out);
string str;
f >> str; // read the first word
// write a well known text
f.seekg(0, ios::cur);
f << "hello world";
f.seekp(0, ios::cur);
f >> str; // and read again
Since a seek or clear operation is required between alternating
read and write (extraction and insertion) operations on the same file it is
not possible to execute a series of << and >> operations in one
expression statement.
Of course, random insertions and extractions are hardly ever used. Generally,
insertions and extractions take place at specific locations in the file. In
those cases, the position where the insertion or extraction must take place
can be controlled and monitored by the
seekg(),
seekp(),
tellg()
and
tellp() member functions (see sections 5.4.1.2 and
5.5.1.2).
Error conditions (see section 5.3.1) occurring due to, e.g., reading
beyond end of file, reaching end of file, or positioning before begin of file,
can be cleared using the
clear() member function. Following clear()
processing may continue. E.g.,
fstream f("filename", ios::in | ios::out);
string str;
f.seekg(-10); // this fails, but...
f.clear(); // processing f continues
f >> str; // read the first word
A common situation in which files are both read and written occurs in
database applications, where files consists of records of fixed
size, and where the location and size of pieces of information is well
known. For example, the following program may be used to add lines of text to
a (possibly existing) file, and to retrieve a certain line, based on its
order-number from the file. Note the use of the
binary file index to
retrieve the location of the first byte of a line.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void err(char const *msg)
{
cout << msg << endl;
return;
}
void err(char const *msg, long value)
{
cout << msg << value << endl;
return;
}
void read(fstream &index, fstream &strings)
{
int idx;
if (!(cin >> idx)) // read index
return err("line number expected");
index.seekg(idx * sizeof(long)); // go to index-offset
long offset;
if
(
!index.read // read the line-offset
(
reinterpret_cast<char *>(&offset),
sizeof(long)
)
)
return err("no offset for line", idx);
if (!strings.seekg(offset)) // go to the line's offset
return err("can't get string offet ", offset);
string line;
if (!getline(strings, line)) // read the line
return err("no line at ", offset);
cout << "Got line: " << line << endl; // show the line
}
void write(fstream &index, fstream &strings)
{
string line;
if (!getline(cin, line)) // read the line
return err("line missing");
strings.seekp(0, ios::end); // to strings
index.seekp(0, ios::end); // to index
long offset = strings.tellp();
if
(
!index.write // write the offset to index
(
reinterpret_cast<char *>(&offset),
sizeof(long)
)
)
return err("Writing failed to index: ", offset);
if (!(strings << line << endl)) // write the line itself
return err("Writing to `strings' failed");
// confirm writing the line
cout << "Write at offset " << offset << " line: " << line << endl;
}
int main()
{
fstream index("index", ios::trunc | ios::in | ios::out);
fstream strings("strings", ios::trunc | ios::in | ios::out);
cout << "enter `r <number>' to read line <number> or "
"w <line>' to write a line\n"
"or enter `q' to quit.\n";
while (true)
{
cout << "r <nr>, w <line>, q ? "; // show prompt
index.clear();
strings.clear();
string cmd;
cin >> cmd; // read cmd
if (cmd == "q") // process the cmd.
return 0;
if (cmd == "r")
read(index, strings);
else if (cmd == "w")
write(index, strings);
else
cout << "Unknown command: " << cmd << endl;
}
}
As another example of reading and writing files, consider the following
program, which also serves as an illustration of reading an
ASCII-Z
delimited string:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{ // r/w the file
fstream f("hello", ios::in | ios::out | ios::trunc);
f.write("hello", 6); // write 2 ascii-z
f.write("hello", 6);
f.seekg(0, ios::beg); // reset to begin of file
char buffer[100]; // or: char *buffer = new char[100]
char c;
// read the first `hello'
cout << f.get(buffer, sizeof(buffer), 0).tellg() << endl;;
f >> c; // read the ascii-z delim
// and read the second `hello'
cout << f.get(buffer + 6, sizeof(buffer) - 6, 0).tellg() << endl;
buffer[5] = ' '; // change asciiz to ' '
cout << buffer << endl; // show 2 times `hello'
}
/*
Generated output:
5
11
hello hello
*/
A completely different way to both read and write to streams can be
implemented using the
streambuf members of stream objects. All
considerations mentioned so far remain valid: before a read operation
following a write operation seekg() must be used, and before a write
operation following a read operation seekp() must be used. When the
stream's streambuf objects are used, either an istream is associated
with the streambuf object of another ostream object, or vice
versa, an ostream object is associated with the streambuf object of
another istream object. Here is the same program as before, now using
associated streams:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void err(char const *msg); // see earlier example
void err(char const *msg, long value);
void read(istream &index, istream &strings)
{
index.clear();
strings.clear();
// insert the body of the read() function of the earlier example
}
void write(ostream &index, ostream &strings)
{
index.clear();
strings.clear();
// insert the body of the write() function of the earlier example
}
int main()
{
ifstream index_in("index", ios::trunc | ios::in | ios::out);
ifstream strings_in("strings", ios::trunc | ios::in | ios::out);
ostream index_out(index_in.rdbuf());
ostream strings_out(strings_in.rdbuf());
cout << "enter `r <number>' to read line <number> or "
"w <line>' to write a line\n"
"or enter `q' to quit.\n";
while (true)
{
cout << "r <nr>, w <line>, q ? "; // show prompt
string cmd;
cin >> cmd; // read cmd
if (cmd == "q") // process the cmd.
return 0;
if (cmd == "r")
read(index_in, strings_in);
else if (cmd == "w")
write(index_out, strings_out);
else
cout << "Unknown command: " << cmd << endl;
}
}
Please note:
streambuf objects of
existing streams are not
ifstream or
ofstream objects (or, for that
matter, istringstream or ostringstream objects), but basic
istream and
ostream objects.
streambuf object does not have to be defined in an
ifstream or
ofstream object: it can be defined outside of the streams,
using constructions like:
filebuf fb("index", ios::in | ios::out | ios::trunc);
istream index_in(&fb);
ostream index_out(&fb);
ifstream object can be constructed using stream
modes normally used for writing to files. Conversely, ofstream objects can
be constructed using stream modes normally used for reading from files.
istream and ostreams are associated through a common
streambuf, then the read and write pointers (should) point to the same
locations: they are tightly coupled.
streambuf over a predefined
fstream object is (of course) that it opens the possibility of using
stream objects with specialized streambuf objects. These streambuf
objects may then specifically be constructed to interface particular
devices. Elaborating this is left as an
exercise to the reader.