11The I/O Stream Library and Input/Output

As in the C language, there is no input/ output statement in C++. However, there is an object-oriented input/output software package in C++, i.e., the I/O stream library. Stream is the key concept of an I/O stream. In this chapter, the concept of stream and then the structure and the use of stream library will be introduced. A more detailed explanation and description of classes and the members of the stream library can be found in the reference book of the running libraries of compiler system.

11.1I/O Stream’s Concept and the Structure of a Stream Library

An I/O stream library is a replacement product of the C language I/O function in object-oriented program design.

As introduced in Chapter 2, we conceptualize the flow from one object to another as “stream” in C++. The operation of getting data from a stream is called extraction, and adding data into a stream is called insertion. Data input and output is realized through an I/O stream. We will give a detailed introduction of it in the following paragraphs.

When a program exchanges information with the external environment, there are two objects: one is the object in the program, and the other is the file object. Stream is a kind of abstract, which is responsible for establishing the connection between the producer of data and the consumer of data, and managing the flow of data. A program generates a stream object and designates this stream object to be associated with a file object, the program operates the stream object, and the stream object affects the connected file object through the file system. Since a stream object is the exchanging interface between objects in the program and file objects, and a stream object has all the properties of a file object, programs regard a stream object as a form of file object.

Operating systems handle the keyboard, screen, printer, and communication port as extended files by using a device driver. Therefore, for a C++ programmer, these devices are the same as disk files. Data exchange with these devices is achieved by using an I/O stream.

Stream is not limited to I/O operations. Every operation of transmitting data from one place to another is a stream operation. For example, both Internet data exchange and process data exchange are stream operations. Therefore, reading an operation is called extraction in stream data abstraction, and writing an operation is called insertion.

The basis of an I/O stream library is class templates. Class templates provide most of the functions in the library, and they can operate on different types of elements. All these templates have “basic_” as the prefix in their names.

There are two kinds of template in an I/O stream: wide-character-oriented and narrow-character-oriented. The wide-character-oriented class supports multibyte characters, and the narrow-character-oriented class supports single-byte characters. The following instantiation types are defined in head file <iosfwd>:

Fig. 11.1: Hierarchy chart of I/O stream class.

It is unnecessary to include the head file <iosfwd> explicitly, because <iosfwd> is already included in other related head files. <iosfwd> is necessary only when a specific type definition is needed, but the corresponding class definition is not needed.

In an I/O stream library, the head file <iostream> declared eight reprocessing stream objects for accomplish input/output operations on standard devices. These objects are cin, out, cerr, clog, wcin, wcout, wcerr, and wclog.

Figure 11.1 shows the relationship among the narrow-character-oriented classes in an I/O stream library. Table 11.1 shows descriptions of these classes and the name of the head file that contains the corresponding class definition. The relation among wide-character-oriented classes is similar to narrow-character-oriented classes, but due to space limitation, we will only introduce the narrow-character-oriented I/O stream class in this chapter.

The head files <ios>, <istream>,<ostream>,<streambuf>, and <iosfwd> in Table 11.1 usually will not be shown in the source program explicitly, because all of them describe the basic types in class hierarchy structure, and they are already included in the head files of other derived classes.

11.2Output Stream

An output stream object is the target of information flow. The three most important output streams are ostream, ofstream, and ostringstream respectively.

The predefined ostream class object is used to accomplish the output to standard devices:

cout standard output

cerr standard error output. It has no buffer area, and outputs the content sent to it immediately.

clog is similar to cerr, but it has a buffer area. It outputs the content when the buffer area is full.

ofstream class supports disk file output. An ofstream class object can be constructed for an output-only disk file. An ofstream object can be designated to receive binary or text data before or after opening a file. Many format options and member functions of ofstream objects can be used, including all the functions in the basic classes ios and ostream.

When a file name is included in the constructor of ofstream, the file will be opened automatically when constructing this ofstream object. You can also use the member function open to open the file after calling the default constructor, or construct an ofstream object based on an opened file that is marked by a file identifier.

Tab. 11.1: I/O Stream Class List.

Class name Description File included
Abstract stream basic type Ios Stream base type ios
Input stream class
Istream Common use input stream class and other input stream basic class istream
Ifstream Input file stream class fstream
Istringstream Input character string stream class sstream
Output stream class
Ostream Common use output stream class and other output stream basic class ostream
Ofstream Output file stream class fstream
Ostringstream Output character string stream class sstream
Input/output stream class
Iostream Common use input/output stream class and other input/output stream basic class istream
Fstream Input/output file stream class fstream
Stringstream Input/output character string stream class sstream
Stream buffer class
Streambuf Abstract stream buffer basic class streambuf
Filebuf Stream buffer class of disk files fstream
Stringbuf Stream buffer class of character string sstream

11.2.1Construct Output Object

If only the predefined objects of cout, cerr, or clog are used, it is not necessary to construct an output stream. For example, in the examples of the previous chapter, we use cout to output the information to standard output devices. To use file stream to output information to a file, a constructor should be used to establish stream objects. An often-used method to construct output file stream is to use the default constructor, and then call the member function open as shown in the following example:

or:

Specify file name and mode when calling constructor:

You can also use one stream to open different files one after another (only one is opened at the same time):

We will introduce the member functions open(), close(), and the modes of opening files later in this chapter.

11.2.2The Use of Inserter and Manipulator

In this section, we will introduce how to control the form of output and how to build inserter operators for a user defined class. Operator << is predefined to all standard C++ data types and is used to transmit bytes to an output stream object. Using << with predefined manipulators can control the output form.

A lot of manipulators are defined in class ios_base (such as hex()) and the head file of <iomanip> (such as setprecision()).

1.Output Width

To modulate output, we can insert the manipulator setw in the stream or call member function width to specify the output width of each item. The following example is of output data with a width of 10 characters and a right-aligned mode:

Example 11.1: Use function width to control output width.

The result of the program is as follows:

From the results we can see that the program added leading space before values that are less than 10 characters wide.

Blank is the default filler. When the output data cannot satisfy the specified width, the system will fill it with blanks automatically. By using the member function fill, other characters can be set as the filler to fill. To use an asterisk to fill the row, for example, we changed the for loop in Example 11.1 to the following:

The result of the program is as follows:

The manipulator setw can be used to specify the width for different data items in the same row, as shown in the following example.

Example 11.2: Use manipulator setw to appoint width.

The member function width is declared in iostream. If setw is used with parameters or any other manipulators, it must include iomanip. On the output line, the width of a character string is set to six and that of an integer is set to 10, as shown below.

Neither setw nor width can truncate values. If there are more digits than the specified width, all digits will be displayed with the proper precision set of the stream. setw and width only affect the scope of the first output after the instruction is executed. After the first output, the width reverts back to its default value. All other stream form options remain effective until they are changed.

2.Alignment

The default output is right-aligned text. The following program is modified in order to achieve an output with left-aligned names and right-aligned values.

Example 11.3: Set alignment.

Result:

This program used manipulator setiosflags with parameters to set left alignment. setiosflags is defined in <iomanip>. Parameter ios_base::left is an enumeration constant; it is defined in class ios_base, therefore needs to include ios_base::prefix when quoting. Manipulator resetiosflags is used to close the left alignment label here. Unlike width and setw, setiosflags remains effective until resetiosflags resumes the default value.

The parameter of setiosflags is the format designator of the stream and its value is specified by the mask code (ios_base enumeration type constant) shown below. The value can be combined by using bitwise or the (|) operator.

ios_base::skipws skip the blanks in input

ios_base::left display left-alignment value, and use filler character to fill the right

ios_base::right display right-alignment value, and use filler character to fill the left (default alignment)

ios_base::internal insert specified filler inside the specified width, after the specified prefix symbol, before the value.

ios_base::dec format the value in decimal form (default form)

ios_base::oct format the value in octal form

ios_base::hex format the value in hexadecimal form

ios_base::showbase insert prefix symbol to represent the form (decimal, octal, or hexadecimal) of integrals.

ios_base::showpoint display the decimal point and tail 0s of float value

ios_base::uppercase display capital letters A~F for hexadecimal form, and display capital letter E for scientific form

ios_base::showpos display the positive sign (+) for nonnegative numbers

ios_base::scientific display float numbers in scientific form

ios_base::fixed display float numbers in fixed-point form (no index part)

ios_base::unitbuf dump and delete the contents in buffer after each insertion

3.Precision

The default value of a float number output precision is 6. For example, 3466.9768 is displayed as 3466.98. We can use the manipulator setprecision (defined in head file <iomanip>) to change the precision by using either the label, ios_based::fixed or ios_based::scientific. If it is set to ios_base::fixed, the output will be 3466.976800; if it is set to ios_base::scientific, the output will be 3.4669773+003. The program above can be modified to display floating point numbers with a precision of 1 as shown in the following example.

Example 11.4: Control output precision.

The result of the program is as follows:

To use the fixed-point format instead of the scientific form, the following statement should be inserted before the for loop:

The result of the program using a fixed-point format with a precision of 1 is shown below:

If ios_base::fixed is changed to ios_base::scientific, the result is as follows:

Note that this program outputs one digit after the decimal point. This indicates that when either ios_base::fixed or ios_base::scientific is used, the precision value is the number of digits after the decimal point. In other cases, the precision value is the number of all the effective digits. Manipulator reseriosflags can be used to delete these labels.

4.Notation

dec, oct, and hex manipulators set the default notation of input and output. For example, if the manipulator hex is inserted into the output stream, the output will be in a hexadecimal format. If ios_base::uppercase (default) label is cleared, the hex numbers a through f are displayed in lowercase; otherwise they are displayed in uppercase. The default notation is dec (decimal).

11.2.3Output File Stream Member Function

There are three types of member functions in the output stream classes:

  1. Member functions equivalent to manipulators;
  2. Member functions executing unformatted write operations;
  3. Other member functions that modify stream state and are not equal to manipulators or inserters.

Inserters and manipulators can be used in ordinal formatted outputs. For random binary disk outputs, other member functions should be used.

1.Function open of output stream

To use an output file stream(ofstream), the stream should be related to a specified disk file in the constructor or function open. In both cases, the parameters of the described files are the same.

When a file related to an output stream is opened, an open mode label is often needed as shown in Table 11.2. These labels can be combined by using a bitwise or (|) operator. They are defined as enumeration constant in class ios_base.

2.Function close of output stream

Member function close closes a disk file related to an output file stream. To complete the disk output, the file must be closed after being used. Although an ofstream destructor will finish closing it automatically, if we want to open another file by the same stream object, we have to use the function close.

Tab. 11.2: Opening Model of Output File Stream File.

Label Function
ios_base::app Open an output file to add data at the bottom.
ios_base::ate Open an extant file (used for input or output) and search its end.
ios_base::in Open an input file, to ofstream files, use ios_base::in as an open mode to avoid deleting the contents of an extant file.
ios_base::out Open a file used for output. To all ofstream objects, this mode is implicit.
ios_base::trunc Open a file. If it already exists, delete the intrinsic content. If ios_base::out is appointed, but ios_base::ate, ios_base::app and ios_base::in are not appointed, then this mode is implicit.
ios_base::binary Use binary mode to open a file (textmode is the default mode).

If the constructor or member function open is used to open this file, the destructor of the output stream will automatically close a stream’s file.

3.Function put

Function put writes a character to the output stream. The default of the following two statements are the same, but the second one is impacted by the format parameter of the stream:

4.Function write

Function write writes a part of memory content to the output file stream. The length parameter indicates the number of bytes. The following example builds an output file stream and writes the binary value of structure Date into a file.

Example 11.5: Output to a file.

Function write will not stop when it encounters space characters and therefore it can read-in a whole class structure. This function has two parameters: one char pointer (indicates the starting address of memory data) and the number of bytes that need to be written. Note that you need char* to cast type before the address of the structure object.

5.Function seekp and tellp

An output file stores an internal pointer to indicate the location of the next read/write operation. Member function seekp is used to set this pointer so it can output to a random location in a disk file. Member function tellp returns the value of the pointer of this file location.

6.Error Handling Function

The role of error handling function is to handle errors when writing a stream. Table 11.3 shows the functions and their effects.

Operator ! has been reloaded. Its role is the same as function fail, therefore expression if (!cout) equals if (cout.fail())...

Operator void*() has also been reloaded. It does the opposite of what the operator ! does. The expression if (cout) has the same effect as the expression if (!cout.fail())...

Operator void*() is not equivalent to good because it does not detect the ending of a file.

Tab. 11.3: Error Handling Functions and Their Effects.

Function Effect and return value
bad If an error appeared and cannot be recovered, then return a non-0 value.
fail If an error that cannot be recovered or an expected condition appeared, for example, a conversion error or cannot find file, then return a non-0 value. Error label will be deleted after call clear using zero parameter.
good If all the error labels and file ending labels have been cleared, then return a non-0 value.
eof Meet the file ending condition, and return a non-0 value.
clear Set the state of internal errors, if called by default parameters, then clear all the error digits.
rdstate Return the current error state.

11.2.4Binary Output File

The original purpose of stream was to use it to process text and therefore the default output mode is text. In text mode output, a line break (decimal 10) will be extended to a new line break (decimal 13) automatically. This can cause problems shown in the following program.

When 10 is output to a file, it will be converted to 13 automatically. However, this conversion is not needed here. To solve this problem, we have to use binary mode output. The characters are not converted while using binary mode output. There are two ways to use binary mode to output to a file as shown below:

1.Use the mode parameter in ofstream constructor to specify binary output mode as shown in the following example:

2.Use function open with a binary mode label to open a file as shown in the following example:

11.3Input Stream

An input stream object is the source of a data flow. The three most important input streams are istream, ifstream, and istringstream.

Class istream ismost suitable for ordered text mode input. All the functions of the basic class ios are included in istream. We rarely need to construct objects from class istream. We usually use predefined a cin object, which is actually an object of class istream_withassign.

Class ifstream supports disk file input. For an input-only disk file, one can construct a class ifstream object, and set its mode to text or binary. If a file name is specified in the constructor, the file will be opened automatically when constructing this object or the member function open can be used to open the file after calling the default constructor. Many format options and member functions of ifstream objects can be used, including all the functions in the basic classes ios and istream.

11.3.1Construct Input Stream Object

It is unnecessary to construct an input stream object if only the predefined object cin is used. If a file stream is needed to read information from file, a constructor should be used to establish a stream object. Two commonly used methods for constructing input file streams are shown below:

1.Use the default constructor, and then call member function open to open the file as shown in the following example:

2.Specify the file name and mode when calling the constructor to build a file stream object, and open the file during constructing:

11.3.2Extraction Operator

The extraction operator (>>) has been predefined for all standard C++ data types. It is the easiest way to get bytes from an input stream object.

The extraction operator (>>) is used to form text input. The space character is used as a delimiter when extracting data. For a text passage with the space character, it is inconvenient to use the extraction operator. In such a case, unformatted input member function getline can be used to read a block of text for analysis. Another method is to derive an input stream class that has a member function like GetNextToken and use it to call istream member to extract and form character data.

The error handling functions of an output stream can also be applied to an input stream. It is very important to test errors in extraction.

11.3.3Input Stream Manipulator

Manipulators defined in the class ios_base and head file <iomanip> can be applied to the input stream. However, only a few manipulators can really impact input stream objects. The most important ones are notation manipulators dec, oct, and hex.

The hex manipulator can receive and handle many different kinds of input stream forms in extraction. For example c, C, 0xc, 0xC, 0Xc, and 0XC can all be interpreted as 12 in hexadecimals. Any character except 0~9, A~F, a~f, and X can lead to the termination of a change in value. For example, sequence 124n5 can change into value 124, and the sets ios_base::fail.

11.3.4Input Stream Member Function

Input stream member functions can be used to input disk files. These member functions include:

functionopen

function get

functiongetline

function read

functionseekg and function tellg

function close

1.Function open of input stream

To use an input file stream (ifstream), the stream must be related to a special disk file through the constructor or by using function open. In either case, the parameters are the same.

When opening a file to be related to the input stream, a mode label is usually specified. Mode labels are shown in Table 11.4. Labels can be combined using bitwise or (|) operators.

2.Function close of input stream

The member function close closes the disk file related to an input file stream.

Tab. 11.4: Opening Mode of Input File Stream File.

ios_base::in Open file used for input (default)
ios_base::binary Use binary mode (the default mode is text mode) to open file

Although the destructor of the class ifstream can close files automatically, if the same stream object is used to open another file, the function close should be used to close the current file first.

3.Function get

The function of the unformatted function get is similar to the extraction operator (>>), the main difference being that the function get includes blanks while reading data, while the extraction operator refuses to receive blanks under the default condition. The following is an example of the function get.

Example 11.6: Example of the function get.

If the following string is entered

the program generates the following output:

When entering “Ctrl+z”, the value read by the program is EOF, which ends the program.

4.Function getline

The member function getline allows an input stream to read multiple characters, and it allows the programmer to specify the input termination character (the default value is a line feed character). The program will delete this termination character from the contents after reading. The following example shows a way to specify the termination character.

Example 11.7: Specification of termination character for input stream.

This program reads a string of characters continuously and stops when it encounters the character ‘t’. The number of characters is limited to 99.

5.Function read

Member function read reads bytes from one file to a designated memory area. The number of bytes that need to be read is determined by the length parameter. If given a length parameter, the read operation will end when the file ends or when the function encounters a file-ending label character in the text mode files.

Example 11.8: Read a binary record from the file payroll into a structure.

The data record here is formatted using the defined structure and there is no termination entered or new line character.

The result of the program is as follows:

6.Functions seekg and tellg

The input file stream keeps an internal pointer that points to the position of the data that is to be read next. Function seekg is used to set this pointer.

Example 11.9: Use function seekg to set position pointer.

The function seekg can be used to achieve an object-oriented data management system. The position of the last byte of the file can be determined by multiplying the fixed-length record size by the number of records. With this number, the record can be read by using get.

Member function tellg returns the position of the current reading pointer; the value is of the streampos type.

Example 11.10: Read a file and display the position of the blanks inside.

11.4Input/output Stream

An iostream object can be the source or destination of data. The two important I/O streams fstream and stringstream are both derived from iostream. These classes inherit the functions istream and ostream described above.

Class fstream supports the input and output of disk files. To read or write a special disk file, an fstream object should be constructed. An fstream object is a single stream that has two logic substreams: one is used for input and the other is used for output. A detailed explanation can be found from online help or reference books of a running library.

11.5Example-improve Employee Information Management System

We have used an employee information management system in examples in the previous chapters. In those examples, the relevant information was stored in the memory at all times and, therefore, the information would be lost when the program ends. How can we save the information permanently? For this, we need to use files. Example 11.11 shows an improved program that can permanently store the information into a file.

Example 11.11: Employee information management.

The program includes three files: class definition head file employee.h, class implementation file empfunc.cpp, and main function file 11_11.cpp. 11_11.cpp and employee.cpp are linked after compiling. If the development environment is VC++, 11_11.cpp and employee.cpp should be put in the same project. The following code is the source code of 11_11.cpp:

The result of the program is as follows:

The program writes the employee information that is stored in the vector to a file, reads the file, and displays the information.

11.6Summary

We first introduced the concept of stream in this chapter, and then introduced the structure and the use of a stream class library. There are no input/ output statements in C++ language, but there is an I/O software package that is object-oriented in C++ compiling system, i.e., I/O stream class library. Stream is the central concept of I/O stream class. It is a kind of abstract. It is responsible for connecting the producers and the consumers of data and managing the flow of data. The program regards stream objects as forms of file objects.

An output stream object is the target of information flow. The three most important output streams are ostream, ofstream, and ostringstream.

An input stream object is the origin of data flow. The three most important input streams are istream, ifstream, and istringstream.

An iostream object is the origin or destination of data. The two important I/O stream classes fstream and stringstream are derived from iostream.

We only introduced the concept and simple applications of stream class library. Readers should refer to a class library reference manual or online help for more details.

Exercises

11.1 What is a stream? What is the extraction and insertion of a stream? What is the function of an I/O stream in C++?

11.2 What is the difference between cerr and clog?

11.3 Use an I/O stream text mode to create a file named test1.txt, write characters “Write files successfully!”, and open it with other word processors (such as Notepad in Windows), see if it has been written correctly.

11.4 Use an I/O stream text mode to open the file test1.txt created above, read the content, and display it to see if it is right.

11.5 Use an I/O stream text mode to open the file test1.txt created above, add characters “Add characters successfully!” after the file, then read the whole file and display the content to see if it is right.

11.6 Define a class dog, including two member variables weight, height and their corresponding member functions, declare an example dog1, whose weight is 5 and age is 10, use an I/O stream to write dog1 into the disk file, and then declare another example dog2, and assign the state of dog1 to dog2 by reading. Use text mode and binary mode to operate on the file respectively; analyze the difference of the result and the ASCII code of the disk file.

11.7 Observe the following program, explain the function of each statement, and write down the result of the program.

11.8 Write a program in which the user inputs a decimal integral and receives results in its decimal, octal and hex forms.

11.9 Write a program that achieves the following function: open a designated text file and add a row number before every line.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset