0.INDEX&INTRODUCING
ChaPTEr 13: DEMYSTIFYING C++ I/O 409
Using Streams 410
What Is a Stream, Anyway? 410
Stream Sources and Destinations 411
Output with Streams 411
Output Basics 412
Methods of Output Streams 412
Handling Output Errors 414
Output Manipulators 415
Input with Streams 417
Input Basics 417
Handling Input Errors 418
Input Methods 419
Input Manipulators 423
Input and Output with Objects 423
String Streams 425
File Streams 426
Text Mode versus Binary Mode 427
Jumping around with seek() and tell() 428
Linking Streams Together 430
Bidirectional I/O 431
Summary 432
Please note that all the code examples for this chapter are available as a part of this chapter’s
code download on the book’s website at www.wrox.com/go/proc++4e on the Download
Code tab.
A program’s fundamental job is to accept input and produce output. A program that produces
no output of any sort would not be very useful. All languages provide some mechanism for
I/O, either as a built-in part of the language or through an OS-specific API. A good I/O sys-
tem is both flexible and easy to use. Flexible I/O systems support input and output through a
variety of devices, such as files and the user console. They also support reading and writing of
different types of data. I/O is error-prone because data coming from a user can be incorrect or
the underlying file system or other data source can be inaccessible. Thus, a good I/O system is
also capable of handling error conditions.
If you are familiar with the C language, you have undoubtedly used printf() and scanf() .
As I/O mechanisms, printf() and scanf() are certainly flexible. Through escape codes and
variable placeholders, they can be customized to read in specially formatted data, or output
any value that the formatting codes permit, which is currently limited to integer/character val-
ues, floating point values, and strings. However, printf() and scanf() falter on other mea-
sures of good I/O systems. They do not handle errors particularly well, they are not flexible
enough to handle custom data types, and in an object-oriented language like C++, they are not
at all object oriented.
1.USING STREAMS
The stream metaphor takes a bit of getting used to. At first, streams may seem more complex than traditional C-style I/O, such as printf() . In reality, they seem complicated initially only because there is a deeper metaphor behind streams than there is behind printf() . Don’t worry, though; after a few examples, you’ll never look back.
1.1 What Is a Stream, Anyway?
Chapter 1 compares the cout stream to a laundry chute for data. You throw some variables
down the stream, and they are written to the user’s screen, or console. More generally,
all streams can be viewed as data chutes. Streams vary in their direction and their
associated source or destination. For example, the cout stream that you are already
familiar with is an output stream, so its direction is “out.” It writes data to the
console so its associated destination is “console.” The c in cout does not stand for
“console” as you might expect, but stands for “character” as it’s a character-based
stream. There is another standard stream called cin that accepts input from the user.
Its direction is “in,” and its associated source is “console.” As with cout , the c
in cin stands for “character.” Both cout and cin are predefined instances of streams
that are defined within the std namespace in C++. The following table gives a brief
description of all predefined streams.
The difference between buffered and unbuffered streams is that a buffered stream does
not immediately send the data to the destination, but instead, it buffers incoming data
and then sends it in blocks. An unbuffered stream, on the other hand, immediately sends
the data to the destination.Buffering is usually done to improve performance, as certain
destinations, such as files, perform better when writing bigger blocks at once. Note
that you can always force a buffered stream to send all its currently buffered data to
the destination by flushing its buffer using the flush() method.