course of C++ programming language
lecture 12, 13: streams
C++ streams
A stream is a logical device that either produces or consumes information. A stream is linked to a physical device by the I/O system. All streams behave in the same way even though the actual physical devices they are connected to may differ substantially. Because all streams behave the same, the same I/O functions can operate on virtually any type of physical device. For example, you can use the same function that writes to a file to write to the memory or to the screen. The advantage to this approach is that you need learn only one I/O system.
Standard C++ provides support for its I/O system in
<iostream>
.
In this header, a rather complicated set of class hierarchies is defined that
supports I/O operations.
The I/O classes begin with a system of template classes.
A template class defines the form of a class without fully specifying the data
upon which it will operate.
Once a template class has been defined, specific instances of it can be
created.
As it relates to the I/O library, Standard C++ creates two specializations of
the I/O template classes: one for 8-bit characters (of type char
)
and another for wide characters (of type wchar_t
).
We will use only the 8-bit character classes since they are by far the most
common.
But the same techniques apply to both.
The C++ I/O system is built upon two related but different template class
hierarchies.
The first is derived from the low-level I/O class called
basic_streambuf
.
This class supplies the basic, low-level input and output operations, and
provides the underlying support for the entire C++ I/O system.
Unless you are doing advanced I/O programming, you will not need to use
basic_streambuf
directly.
The class hierarchy that you will most commonly be working with is derived from
basic_ios
.
This is a high-level I/O class that provides formatting, error checking, and
status information related to stream I/O.
A base class for basic_ios
is called ios_base
, which
defines several nontemplate traits used by basic_ios
.
basic_ios
is used as a base for several derived classes, including
basic_istream
, basic_ostream
, and
basic_iostream
.
These classes are used to create streams capable of input, output, and
input/output, respectively.
template class | character-based class | wide-character-based class |
---|---|---|
basic_streambuf | streambuf | wstreambuf |
basic_ios | ios | wios |
basic_istream | istream | wistream |
basic_ostream | ostream | wostream |
basic_iostream | iostream | wiostream |
basic_fstream | fstream | wfstream |
basic_ifstream | ifstream | wifstream |
basic_ofstream | ofstream | wofstream |
Predefined streams
When a C++ program begins execution, four built-in streams are automatically
opened.
Streams cin
, cout
, and cerr
correspond
to C's stdin
, stdout
, and stderr
.
By default, the standard streams are used to communicate with the
console.
stream | meaning | default device |
---|---|---|
cin | standard input | keyboard |
cout | standard output | screen |
cerr | standard error output | screen |
clog | buffered version of cerr | screen |
Standard C++ also defines these four additional streams: win
,
wout
, werr
, and wlog
.
These are wide-character versions of the standard streams.
Wide characters are generally 16-bit quantities.
Wide characters are used to hold the large character sets associated with some
human languages.
Formating using the ios
members
Each stream has associated with it a set of format flags that control the way
information is formatted.
The ios
class declares a bitmask enumeration called
fmtflags
in which the following values are defined.
Technically, these values are defined within ios_base
, which is
a base class for ios
.
adjustfield | basefield | boolalpha |
dec | fixed | floatfield |
hex | internal | left |
oct | right | scientific |
showbase | showpoint | showpos |
skipws | unitbuf | uppercase |
These values are used to set or clear the format flags.
-
When the
skipws
flag is set, leading white-space characters (spaces, tabs, and newlines) are discarded when performing input on a stream. Whenskipws
is cleared, white-space characters are not discarded. -
When the
left
flag is set, output is left justified. When theright
is set, output is right justified. When theinternal
flag is set, a numeric value is padded to fill a field by inserting spaces between any sign or base character. If none of these flags are set, output is right justified by default. -
By default, numeric values are output in decimal.
However, it is possible to change the number base.
Setting the
oct
flag causes output to be displayed in octal. Setting thehex
flag causes output to be displayed in hexadecimal. To return output to decimal, set thedec
flag. -
Setting
showbase
causes the base of numeric values to be shown. For example, if the conversion base is hexadecimal, the value 1F will be displayed as 0x1F. -
By default, when scientific notation is displayed, the e is in
lowercase.
Also, when a hexadecimal value is displayed, the x is in lowercase.
When
uppercase
is set, these characters are displayed in uppercase. -
Setting
showpos
causes a leading plus sign to be displayed before positive values. -
Setting
showpoint
causes a decimal point and trailing zeros to be displayed for all floating-point output - whether needed or not. -
By setting the
scientific
flag, floating-point numeric values are displayed using scientific notation. Whenfixed
is set, floating-point values are displayed using normal notation. When neither flag is set, the compiler chooses an appropriate method. -
When
unitbuf
is set, the buffer is flushed after each insertion operation. -
When
boolalpha
is set, booleans can be input or output using the keywords true and false.
Since it is common to refer to the oct
, dec
, and
hex
fields, they can be collectively referred to as
basefield
.
Similarly, the left
, right
, and internal
fields can be referred to as adjustfield
.
Finally, the scientific
and fixed
fields can be
referenced as floatfield
.
To set a flag, use the setf()
function.
This function is a member of ios
.
This function returns the previous settings of the format flags (of type
fmtflags
) and turns on specified flags.
The complement of setf()
is unsetf()
.
This member function of ios
is used to clear one or more format flags.
There is an overloaded form of setf()
that takes this general form
setf(flags1,flags2).
In this version, only the flags specified by flags2 are affected.
They are first cleared and then set according to the flags specified by
flags1.
Note that even if flags1 contains other flags, only those specified by
flags2 will be affected.
The previous flags setting is returned.
There will be times when you only want to know the current format settings but
not alter any.
To accomplish this goal, ios
includes the member function
flags()
, which simply returns the current setting of each format
flag (of type fmtflags
).
The flags()
function has a second form that allows you to set all
format flags associated with a stream.
When you use this version, the bit pattern found in its argument is used to set
the format flags associated with the stream.
Thus, all format flags are affected.
The function returns the previous settings (of type fmtflags
).
Using width()
, precision()
, and fill()
Overloading operator<<
and operator>>
Using manipulators to format I/O
Creating your own manipulators
Unformated I/O
The class ostream
is defined with the operator
<<
(put to) to handle output of the built-in types.
The <<
operator is the most useful part of output streams.
However, there is additional functionality: public methods put()
and write()
.
The put()
and write()
functions simply write
characters.
Input is handled similarly to output.
There is a class istream
that provides an input operator
>>
(get from) for a small set of standard types.
The >>
operator is intended for formatted input.
Where this is not desirable and we want to read characters as characters and
then examine them, we use the get()
or getline()
functions.
The get()
and getline()
functions treat whitespace
characters exactly like other characters.
They are intended for input operations, where one doesn't make assumptions
about the meanings of the characters read.
We prefer getline()
over get()
.
A getline()
behaves like its corresponding get()
,
except that it removes its terminator from the istream
.
When efficiency isn't paramount, it is better to read into
a string
.
In that way, the most common allocation and overflow problems cannot occur.
However, the get()
, getline()
and read()
functions are needed to implement such higher-level facilities.
The ignore()
function reads characters like read()
,
but it doesn't store them anywhere.
Stream state
Every stream (istream
or ostream
) has a state
associated with it.
Errors and nonstandard conditions are handled by setting and testing this state
appropriately.
The stream state is found in basic_istream
's base
basic_ios
from <ios>
:
If the state is good()
the previous input operation succeeded.
If the state is good()
, the next input operation might succeed;
otherwise, it will fail.
Applying an input operation to a stream that is not in the good()
state is a null operation.
If we try to read into a variable v
and the operation fails, the
value of v
should be unchanged (it is unchanged if v
is a variable of one of the types handled by istream
or
ostream
member functions).
The difference between the states fail()
and bad()
is
subtle.
When the state is fail()
but not also bad()
, it is
assumed that the stream is uncorrupted and that no characters have been lost.
When the state is bad()
, all bets are off.
The state of a stream is represented as a set of flags.
Like most constants used to express the behavior of streams, these flags are
defined in basic_ios
' base ios_base
:
The I/O state flags can be directly manipulated.
When a stream is used as a condition, the state of the stream is tested by
operator void*
or operator !
.
The test succeeds only if the state is good()
.
Exceptions in streams
It is not convenient to test for errors after each I/O operation, so a common cause of error is failing to do so where it matters. In particular, output operations are typically unchecked, but they do occasionally fail.
The only function that directly changes the state of a stream is
clear()
.
Thus, an obvious way of getting notified by a state change is to ask
clear()
to throw an exception.
The ios_base
member exceptions()
does just that:
For example,
requests that clear()
should throw
an ios_base::failure
exception if cout
goes into
states bad
, fail
or eof
- in other
words, if any output operation on cout
doesn't perform
flawlessly.
Similarly,
allows us to catch the not-too-uncommon case in which the input is not in the format we expected, so an input operation didn't return a value from the stream.
A call of exceptions()
with no arguments returns the set of I/O
state flags that triggers an exception.
The primary use of I/O exceptions is to catch unlikely - and therefore often
forgotten - errors.
Another is to control I/O.
File streams
Files lend themselves very well to the stream abstraction because reading and
writing files always involves a position in addition to the data.
In C++, the ofstream
and ifstream
classes provide
output and input functionality for files.
They are defined in the header file <fstream>
.
Here is a complete program that copies one file to another. The file names are taken as commandline arguments.
A file is opened for input by creating an object of class ifstream
(input file stream) with the file name as the argument.
Similarly, a file is opened for output by creating an object of class
ofstream
(output file stream) with the file name as the argument.
In both cases, we test the state of the created object to see if the file was
successfully opened.
A file can be explicitly closed by calling close()
on its stream.
However, this is implicitly done by the stream's destructor.
So an explicit call of close()
is needed only if the file must be
closed before reaching the end of the scope in which its stream was declared.
String streams
A stream can be attached to a string
.
That is, we can read from a string
and write to
a string
using the formatting facilities provided by streams.
Such streams are called a stringstream
s.
They are defined in the header file <sstream>
.
An ostringstream
can be used to format message
string
s.
An istringstream
is an input stream reading from
a string
.
References
-
B.Stroustrup: The C++ programming language. Third edition.
Section 21: streams; pp. 605-654. -
H. Schildt: C++: the complete reference. Third edition.
Section 20: the C++ I/O system basics; pp. 511-540.
Section 21: the C++ file I/O; pp. 541-568.