Streams

C++ I/O occurs in streams, which are sequences of bytes. In input operations, the bytes flow from a device (e.g., a keyboard, a disk drive, a network connection) to main memory. In output operations, bytes flow from main memory to a device (e.g., a display screen, a printer, a disk drive, a network connection, etc.).

An application associates meaning with bytes. The bytes could represent characters, raw data, graphics images, digital speech, digital video or any other information an application may require.

The system I/O mechanisms should transfer bytes from devices to memory (and vice versa) consistently and reliably. Such transfers often involve some mechanical motion, such as the rotation of a disk or a tape, or the typing of keystrokes at a keyboard. The time these transfers take is typically much greater than the time the processor requires to manipulate data internally. Thus, I/O operations require careful planning and tuning to ensure optimal performance.

C++ provides both "low-level" and "high-level" I/O capabilities. Low-level I/O capabilities (i.e., unformatted I/O) specify that some number of bytes should be transferred device-to-memory or memory-to-device. In such transfers, the individual byte is the item of interest. Such low-level capabilities provide high-speed, high-volume transfers but are not particularly convenient for programmers.

Programmers generally prefer a higher-level view of I/O (i.e., formatted I/O), in which bytes are grouped into meaningful units, such as integers, floating-point numbers, characters, strings and user-defined types. These type-oriented capabilities are satisfactory for most I/O other than high-volume file processing.


Performance Tip 15.1

Use unformatted I/O for the best performance in high-volume file processing.

Portability Tip 15.1

Using unformatted I/O can lead to portability problems, because unformatted data is not portable across all platforms.

 

15.2.1. Classic Streams vs. Standard Streams

In the past, the C++ classic stream libraries enabled input and output of chars. Because a char occupies one byte, it can represent only a limited set of characters (such as those in the ASCII character set). However, many languages use alphabets that contain more characters than a single-byte char can represent. The ASCII character set does not provide these characters; the Unicode character set does. Unicode is an extensive international character set that represents the majority of the world's commercially viable languages, mathematical symbols and much more. For more information on Unicode, visit www.unicode.org.

C++ includes the standard stream libraries, which enable developers to build systems capable of performing I/O operations with Unicode characters. For this purpose, C++ includes an additional character type called wchar_t, which can store Unicode characters. The C++ standard also redesigned the classic C++ stream classes, which processed only chars, as class templates with separate specializations for processing characters of types char and wchar_t, respectively. We use the char type of class templates with separate specializations throughout this book.

15.2.2. iostream Library Header Files

The C++ iostream library provides hundreds of I/O capabilities. Several header files contain portions of the library interface.

Most C++ programs include the header file, which declares basic services required for all stream-I/O operations. The header file defines the cin, cout, cerr and clog objects, which correspond to the standard input stream, the standard output stream, the unbuffered standard error stream and the buffered standard error stream, respectively. (cerr and clog are discussed in Section 15.2.3.) Both unformatted-and formatted-I/O services are provided.

The header declares services useful for performing formatted I/O with so-called parameterized stream manipulators, such as setw and setprecision.

The header declares services for user-controlled file processing. We use this header in the file-processing programs of Chapter 17.

C++ implementations generally contain other I/O-related libraries that provide system-specific capabilities, such as the controlling of special-purpose devices for audio and video I/O.

15.2.3. Stream Input/Output Classes and Objects

The iostream library provides many templates for handling common I/O operations. For example, class template basic_istream supports stream-input operations, class template basic_ostream supports stream-output operations, and class template basic_iostream supports both stream-input and stream-output operations. Each template has a predefined template specialization that enables char I/O. In addition, the iostream library provides a set of typedefs that provide aliases for these template specializations. The typedef specifier declares synonyms (aliases) for previously defined data types. Programmers sometimes use typedef to create shorter or more readable type names. For example, the statement


typedef Card *CardPtr;

defines an additional type name, CardPtr, as a synonym for type Card *. Note that creating a name using typedef does not create a data type; typedef creates only a type name that may be used in the program. Section 22.5 typedef discusses typedef in detail. The typedef istream represents a specialization of basic_istream that enables char input. Similarly, the typedef ostream represents a specialization of basic_ostream that enables char output. Also, the typedef iostream represents a specialization of basic_iostream that enables both char input and output. We use these typedefs throughout this chapter.

Stream-I/O Template Hierarchy and Operator Overloading

Templates basic_istream and basic_ostream both derive through single inheritance from base template basic_ios. [1] Template basic_iostream derives through multiple inheritance [2] from templates basic_istream and basic_ostream. The UML class diagram of Fig. 15.1 summarizes these inheritance relationships.

[1] Technically, templates do not inherit from other templates. However, in this chapter, we discuss templates only in the context of the template specializations that enable char I/O. These specializations are classes and thus can inherit from each other.

[2] Multiple inheritance is discussed in Chapter 24, Other Topics.

Figure 15.1. Stream-I/O template hierarchy portion.

Operator overloading provides a convenient notation for performing input/output. The left-shift operator (<<) is overloaded to designate stream output and is referred to as the stream insertion operator. The right-shift operator (>>) is overloaded to designate stream input and is referred to as the stream extraction operator. These operators are used with the standard stream objects cin, cout, cerr and clog and, commonly, with user-defined stream objects.


Standard Stream Objects cin, cout, cerr and clog

The predefined object cin is an istream instance and is said to be "connected to" (or attached to) the standard input device, which usually is the keyboard. The stream extraction operator (>>) as used in the following statement causes a value for integer variable grade (assuming that grade has been declared as an int variable) to be input from cin to memory:

cin >> grade; // data "flows" in the direction of the arrows

Note that the compiler determines the data type of grade and selects the appropriate overloaded stream extraction operator. Assuming that grade has been declared properly, the stream extraction operator does not require additional type information (as is the case, for example, in C-style I/O). The >> operator is overloaded to input data items of built-in types, strings and pointer values.

The predefined object cout is an ostream instance and is said to be "connected to" the standard output device, which usually is the display screen. The stream insertion operator (<<), as used in the following statement, causes the value of variable grade to be output from memory to the standard output device:

cout << grade; // data "flows" in the direction of the arrows

Note that the compiler also determines the data type of grade (assuming grade has been declared properly) and selects the appropriate stream insertion operator, so the stream insertion operator does not require additional type information. The << operator is overloaded to output data items of built-in types, strings and pointer values.

The predefined object cerr is an ostream instance and is said to be "connected to" the standard error device. Outputs to object cerr are unbuffered, implying that each stream insertion to cerr causes its output to appear immediatelythis is appropriate for notifying a user promptly about errors.

The predefined object clog is an instance of the ostream class and is said to be "connected to" the standard error device. Outputs to clog are buffered. This means that each insertion to clog could cause its output to be held in a buffer until the buffer is filled or until the buffer is flushed. Buffering is an I/O performance-enhancement technique discussed in operating-systems courses.

File-Processing Templates

C++ file processing uses class templates basic_ifstream (for file input), basic_ofstream (for file output) and basic_fstream (for file input and output). Each class template has a predefined template specialization that enables char I/O. C++ provides a set of typedefs that provide aliases for these template specializations. For example, the typedef ifstream represents a specialization of basic_ifstream that enables char input from a file. Similarly, typedef ofstream represents a specialization of basic_ofstream that enables char output to a file. Also, typedef fstream represents a specialization of basic_fstream that enables char input from, and output to, a file. Template basic_ifstream inherits from basic_istream, basic_ofstream inherits from basic_ostream and basic_fstream inherits from basic_iostream. The UML class diagram of Fig. 15.2 summarizes the various inheritance relationships of the I/O-related classes. The full stream-I/O class hierarchy provides most of the capabilities that programmers need. Consult the class-library reference for your C++ system for additional file-processing information.


Figure 15.2. Stream-I/O template hierarchy portion showing the main file-processing templates.

Категории