- Table of Contents
- Previous Chapter
- Next Chapter

# Chapter 6: The IO-stream Library

Extending the standard stream (`FILE`) approach, well known from the C programming language, C++ offers an input/output (I/O) library based on `class` concepts.

All C++ I/O facilities are defined in the namespace `std`. The `std::` prefix is omitted below, except for situations where this would result in ambiguities.

Earlier (in chapter 3) we've seen several examples of the use of the C++ I/O library, in particular showing insertion operator (<<) and the extraction operator (>>). In this chapter we'll cover I/O 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 class construction has not yet been covered (for that see chapter 7) and although inheritance is not covered formally before chapter 13, it is quite possible to discuss I/O facilities long before the technical background of class construction has been 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 through `using` declarations like:

            using ios = basic_ios<char>;

Since C++ supports various kinds of character types (e.g., `char`, `wchar_t`), I/O facilities were developed using the template mechanism allowing for easy conversions to character types other than the traditional `char` type. As elaborated in chapter 21, this also allows the construction of generic software, that could thereupon be used for any particular type representing characters. So, analogously to the above using declaration there exists a

            using wios = basic_ios<wchar_t>;

This way, `wios` can be used for the `wchar_t` type. Because of the existence of these type definitions, the `basic_` prefix was omitted from the C++ Annotations without loss of continuity. The C++ Annotations primarily focus on the standard 8-bits `char` type.

Iostream objects cannot be declared using standard forward declarations, like:

        class std::ostream;     // now erroneous

Instead, to declare iostream classes the `<iosfwd>` header file should be included:

        #include <iosfwd>       // correct way to declare iostream classes

Using C++ I/O 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, 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. But C++ adds to this I/O based on classes, resulting in type safety, extensibility, and a clean design.

The ANSI/ISO standard specifies architecture independent I/O. Not all of the standard's specifications are covered in this chapter, as they often rely on inheritance and polymorphism, which topics are formally covered by chapters 13 and 14. Some examples are offered in chapter 26, and in this chapter references to specific sections in other chapters are given where appropriate.

Figure 4: Central I/O Classes
This chapter is organized as follows (see also Figure 4):

- The class `ios_base` is the foundation upon which the iostream 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 facilities for output formatting.

- The class `ios` is directly derived from `ios_base`. Every class of the I/O library doing input or output is itself derived from this `ios` class, and therefore inherits its (and, by implication: `ios_base`'s) capabilities. The reader is urged to keep this in mind while reading this chapter. The concept of inheritance is not discussed here, but rather in chapter 13.
  The class `ios` is important because it implements communication with a buffer which is used by streams. This buffer is a `streambuf` object which is responsible for the actual I/O to/from the actually used device, which might be a file, a keyboard, a screen, an Internet connection, etc., etc.. Consequently `iostream` objects do not perform I/O operations themselves, but leave these operations to the (stream)buffer objects with which they are associated.

- Next, basic C++ output facilities are discussed. The basic class used for output operations is `ostream`, defining the insertion operator as well as other facilities writing information to streams. Apart from inserting information into files it is possible to insert information into memory buffers, for which the `ostringstream` class is available. Formatting 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 into streams using manipulators. This aspect of C++ output is discussed as well.

- Basic C++ input facilities are implemented by the `istream` class. This class defines the extraction operator and related input facilities. Comparably to inserting information into memory buffers (using `ostringstream`) a class `istringstream` is available to extract information from memory buffers.

- The class `iostream` combines the facilities offered by `istream` and `ostream`. Thus, `iostream` objects can be used to read and write from the same object.

- The class `fstream` is a frequently encountered example of an `iostream` class: `fstream` objects are used to read and write from the same file, which is often used in programs processing data bases. In this chapter topics like reading and writing from the same stream and mixing C and C++ I/O using `filebuf` objects are also covered. Other I/O related topics are covered elsewhere in the C++ Annotations (cf. section 20.15 and chapter 26).

Stream objects have a limited but important role: they are the interface between, on the one hand, the objects to be input or output and, on the other hand, the `streambuf`, which is responsible for the actual input and output to the device accessed by a `streambuf` object.

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`- and `ostream`-class facilities. It is important to understand the distinction between the formatting roles of iostream objects and the buffering interface to an external device as implemented in a `streambuf` object. Interfacing to new devices (like sockets or file descriptors) requires the construction of a new kind of `streambuf`, rather than 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.

## 6.1: Special header files

Several iostream related header files are available. Depending on the situation at hand, the following header files should be used:

- `iosfwd`: sources should include this header file if only a declaration of the stream classes is required. For example, if a function defines a reference parameter to an `ostream` then the compiler does not need to know exactly what an `ostream` is. When declaring such a function the `ostream` class merely needs to be be declared. One cannot use

      class std::ostream; // erroneous declaration

      void someFunction(std::ostream &str);

  but, instead, one should use:

      #include <iosfwd>   // correctly declares class ostream

      void someFunction(std::ostream &str);

- `<ios>`: sources should include this header file when using types and facilites (like `ios::off_type`, see below) defined in the `ios` class.
- `<streambuf>`: sources should include this header file when using `streambuf` or `filebuf` classes. See sections 14.8 and 14.8.3.
- `<istream>`: sources should include this preprocessor directive when using the class `istream` or when using classes that do both input and output. See section 6.5.1.
- `<ostream>`: sources should include this header file when using the class `ostream` class or when using classes that do both input and output. See section 6.4.1.
- `<iostream>`: sources should include this header file when using the global stream objects (like `cin` and `cout`) and also when defining a stream capable of reading and writing from the same device (see also section 14.8.2).
- `<fstream>`: sources should include this header file when using the file stream classes. See sections 6.4.2, 6.5.2, and 6.6.3.
- `<sstream>`: sources should include this header file when using the string stream classes. See sections 6.4.3 and 6.5.3.
- `<iomanip>`: sources should include this header file when using parameterized manipulators. See section 6.3.2.

## 6.2: The foundation: the class `ios_base'

The class `std::ios_base` forms the foundation of all I/O operations, and defines, among other things, facilities for inspecting the state of I/O streams and most output formatting facilities. Every stream class of the I/O library is, through the class `ios`, derived from this class, and inherits its capabilities. As `ios_base` is the foundation on which all C++ I/O was built, we introduce it here as the first class of the C++ I/O library.

Note 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 does so, and the I/O library therefore represents a de facto I/O standard for C++. Also note that, as mentioned before, the iostream classes themselves are not responsible for the eventual I/O, but delegate this to an auxiliary class: the class `streambuf` or its derivatives.

It is neither possible nor required to construct an `ios_base` object directly. Its construction is always a side-effect of constructing an object further down the class hierarchy, like `std::ios`. `Ios` is the next class down the iostream hierarchy (see Figure 4). Since all stream classes in turn inherit from `ios`, and thus also from `ios_base`, the distinction between `ios_base` and `ios` is in practice not 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`).

## 6.3: Interfacing `streambuf' objects: the class `ios'

The `std::ios` class is 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 seldom 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 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 of the classes `ios` and `ios_base` are also available to other stream classes. Before discussing these additional stream classes, the features offered by the class `ios` (and by implication: by `ios_base`) are now introduced.

In some cases it may be required to include `ios` explicitly. An example is the situations where the formatting flags themselves (cf. section 6.3.2.2) are referred to in source code.

The class `ios` offers several member functions, most of which are related to formatting. Other frequently used member functions are:

- `std::streambuf *ios::rdbuf()`:
  A pointer to the `streambuf` object forming the interface between the `ios` object and the device with which the `ios` object communicates is returned. See sections 14.8 and 26.1.2 for more information about the `class streambuf`.
- `std::streambuf *ios::rdbuf(std::streambuf *new)`:

  > The current `ios` object is associated with another `streambuf` object. A pointer to the `ios` object's original `streambuf` object is returned. The object to which this pointer points is not destroyed when the `stream` object goes out of scope, but is owned by the caller of `rdbuf`.

- `std::ostream *ios::tie()`:
  A pointer to the `ostream` object that is currently tied to the `ios` object is returned (see the next member). The return value 0 indicates that currently no `ostream` object is tied to the `ios` object. See section 6.5.5 for details.
- `std::ostream *ios::tie(std::ostream *outs)`:

  > The ostream object is tied to current `ios` object. This means that the `ostream` object is flushed every time before an input or output action is performed by the current `ios` object. A pointer to the `ios` object's original `ostream` object is returned. To break the tie, pass the argument 0. See section 6.5.5 for an example.

### 6.3.1: Condition states

Operations on streams may fail for various reasons. Whenever an operation fails, further operations on the stream are suspended. It is possible to inspect, set and possibly clear the condition state of streams, allowing a program to repair the problem rather than having to abort. The members that are available for interrogating or manipulating the stream's state are described in the current section.

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`:

- `bool ios::bad()`:

  > the value `true` is returned when the stream's `badbit` has been set and `false` otherwise. If `true` is returned it indicates that an illegal operation has been requested at the level of the `streambuf` object to which the stream interfaces. What does this mean? It indicates that the `streambuf` itself is behaving unexpectedly. Consider the following example:

  >     std::ostream error(0);

  > Here an `ostream` object is constructed without providing it with a working `streambuf` object. Since this ``streambuf`' will never operate properly, its `badbit` flag is raised from the very beginning: `error.bad()` returns `true`.

- `bool ios::eof()`:

  > the value `true` is returned when end of file (`EOF`) has been sensed (i.e., the `eofbit` flag has been set) and `false` otherwise. Assume we're reading lines line-by-line from `cin`, but the last line is not terminated by a final `\n` character. In that case `std::getline` attempting to read the `\n` delimiter hits end-of-file first. This raises the `eofbit` flag and `cin.eof()` returns `true`. For example, assume `std::string str` and `main` executing the statements:

  >     getline(cin, str);
  >     cout << cin.eof();

  > Then

  >     echo "hello world" | program

  > prints the value 0 (no EOF sensed). But after

  >     echo -n "hello world" | program

  > the value 1 (EOF sensed) is printed.

- `bool ios::fail()`:

  > the value `true` is returned when `bad` returns `true` or when the `failbit` flag was set. The value `false` is returned otherwise. In the above example, `cin.fail()` returns `false`, whether we terminate the final line with a delimiter or not (as we've read a line). However, executing another `getline` results in raising the `failbit` flag, causing `cin::fail()` to return `true`. In general: `fail` returns `true` if the requested stream operation failed. A simple example showing this consists of an attempt to extract an `int` when the input stream contains the text `hello world`. The value `not fail()` is returned by the `bool` interpretation of a stream object (see below).

- `bool ios::good()`:

  > the value of the `goodbit` flag is returned. It equals `true` when none of the other condition flags (`badbit, eofbit, failbit`) was 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() << '\n';
  >     }

  >     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, `hello` and `world`, while the second line is not terminated by a `\n` character the following is shown:

  >         Bad: 0 Fail: 1 Eof: 0 Good: 0

  >         Bad: 0 Fail: 0 Eof: 0 Good: 1

  >         Bad: 0 Fail: 0 Eof: 1 Good: 0

  > Thus, extracting `x` fails (`good` returning `false`). Then, the error state is cleared, and the first line is successfully read (`good` returning `true`). Finally the second line is read (incompletely): `good` returning `false`, and `eof` returning `true`.

- Interpreting streams as `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 cin

  > When interpreting a stream as a logical value, it is actually ``not fail()`' that is interpreted. The above examples may therefore 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:

- `void ios::clear()`:

  > When an error condition has occurred, and the condition can be repaired, then `clear` can be used to clear the error state of the file. An overloaded version exists accepting state flags, that are set after first clearing the current set of flags: `clear(int state)`. Its return type is `void`

- `ios::iostate ios::rdstate()`:

  > The current set of flags that are set for an `ios` object are returned (as an `int`). To test for a particular flag, use the bitwise and operator:

  >     if (!(iosObject.rdstate() & ios::failbit))
  >     {
  >         // last operation didn't fail
  >     }

  > Note that this test cannot be performed for the `goodbit` flag as its value equals zero. To test for `good' use a construction like:

  >     if (iosObject.rdstate() == ios::goodbit)
  >     {
  >         // state is `good'
  >     }

- `void ios::setstate(ios::iostate state)`:

  > A stream may be assigned a certain set of states using `setstate`. Its return type is `void`. E.g.,

  >     cin.setstate(ios::failbit);     // set state to `fail'

  > To set multiple flags in one `setstate()` call use the `bitor` operator:

  >     cin.setstate(ios::failbit | ios::eofbit)

  The member `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 `clear` is called.

C++ supports an exception mechanism to handle exceptional situations. According to the ANSI/ISO standard, exceptions can be used with stream objects. Exceptions are covered in chapter 10. Using exceptions with stream objects is covered in section 10.7.

### 6.3.2: Formatting output and input

The way information is written to streams (or, occasionally, read from streams) is controlled by formatting flags.

Formatting is used when it is necessary to, e.g., set the width of an output field or input buffer and to determine the form (e.g., the radix) in which values are displayed. Most formatting features belong to the realm of the `ios` class. Formatting is controlled by flags, defined by the `ios` class. These flags may be manipulated in two ways: using specialized member functions or using manipulators, which are directly inserted into or extracted from streams. There is no special reason for using either method; usually both methods are possible. In the following overview the various member functions are first introduced. Following this the flags and manipulators themselves are covered. Examples are provided showing how the flags can be manipulated and what their effects are.

Many manipulators are parameterless and are available once a stream header file (e.g., `iostream`) has been included. Some manipulators require arguments. To use those latter manipulators the header file `iomanip` must be included.

#### 6.3.2.1: Format modifying member functions

Several member functions are available manipulating the I/O formatting flags. Instead of using the members listed below manipulators are often available that may directly be inserted into or extracted from streams. The available members are listed in alphabetical order, but the most important ones in practice are setf, unsetf and width.

- `ios &ios::copyfmt(ios &obj)`:
  all format flags of `obj` are copied to the current `ios` object. The current `ios` object is returned.
- `ios::fill() const`:
  the current padding character is returned. By default, this is the blank space.
- `ios::fill(char padding)`:

  > the padding character is redefined, the padding character that was used before the redefinition is returned. Instead of using this member function the `setfill` manipulator may be inserted directly into an `ostream`. Example:

  >     cout.fill('0');         // use '0' as padding char
  >     cout << setfill('+');   // use '+' as padding char

- `ios::fmtflags ios::flags() const`:
  the current set of flags controlling the format state of the stream for which the member function is called is returned. To inspect whether a particular flag was set, use the `bit_and` operator. Example:

      if (cout.flags() & ios::hex)
          cout << "Integral values are printed as hex numbers\n"

- `ios::fmtflags ios::flags(ios::fmtflags flagset)`:

  > the previous set of flags are returned and the new set of flags are defined by `flagset`. Multiple flags are specified using the `bitor` operator. Example:

  >             // change the representation to hexadecimal
  >     cout.flags(ios::hex | cout.flags() & ~ios::dec);

- `int ios::precision() const`:
  the number of significant digits used when outputting floating point values is returned (default: 6).
- `int ios::precision(int signif)`:

  > the number of significant digits to use when outputting real values is set to `signif`. The previously used number of significant digits is returned. If the number of required digits exceeds `signif` then the number is displayed in `scientific' notation (cf. section 6.3.2.2). Manipulator: `setprecision`. Example:

  >     cout.precision(3);          // 3 digits precision
  >     cout << setprecision(3);    // same, using the manipulator

  >     cout << 1.23 << " " << 12.3 << " " << 123.12 << " " << 1234.3 << '\n';
  >     // displays: 1.23 12.3 123 1.23e+03

- `ios::fmtflags ios::setf(ios::fmtflags flags)`:

  > sets one or more formatting flags (use the `bitor` operator to combine multiple flags). Already set flags are not affected. The previous set of flags is returned. Instead of using this member function the manipulator `setiosflags` may be used. Examples are provided in the next section (6.3.2.2).

- `ios::fmtflags ios::setf(ios::fmtflags flags, ios::fmtflags mask)`:

  > clears all flags mentioned in `mask` and sets the flags specified in `flags`. The previous set of flags is returned. Some examples are (but see the next section (6.3.2.2) for a more thorough discussion):

  >             // left-adjust information in wide fields:
  >     cout.setf(ios::left, ios::adjustfield);

  >             // display integral values as hexadecimal numbers:
  >     cout.setf(ios::hex, ios::basefield);

  >             // display floating point values in scientific notation:
  >     cout.setf(ios::scientific, ios::floatfield);

- `ios::fmtflags ios::unsetf(fmtflags flags)`:

  > the specified formatting flags are cleared (leaving the remaining flags unaltered) and returns the previous set of flags. A request to unset an active default flag (e.g., `cout.unsetf(ios::dec)`) is ignored. Instead of this member function the manipulator `resetiosflags` may also be used. Example:

  >     cout << 12.24;              // displays  12.24
  >     cout.setf(ios::fixed);
  >     cout << 12.24;              // displays  12.240000
  >     cout.unsetf(ios::fixed);    // undo a previous ios::fixed setting.
  >     cout << 12.24;              // displays  12.24
  >     cout << resetiosflags(ios::fixed);  // using manipulator rather
  >                                         // than unsetf

- `int ios::width() const`:

  > the currently active output field width to use on the next insertion is returned. The default value is 0, meaning `as many characters as needed to write the value'.

- `int ios::width(int nchars)`:

  > the field width of the next insertion operation is set to `nchars`, returning the previously used field width. This setting is not persistent. It is reset to 0 after every insertion operation. Manipulator: `std::setw(int)`. Example:

  >     cout.width(5);
  >     cout << 12;                     // using 5 chars field width
  >     cout << setw(12) << "hello";    // using 12 chars field width

#### 6.3.2.2: Formatting flags

Most formatting flags are related to outputting information. Information can be written to output streams in basically two ways: using binary output information is written directly to an output stream, without converting it first to some human-readable format and using formatted output by which values stored in the computer's memory are converted to human-readable text first. Formatting flags are used to define the way this conversion takes place. In this section all formatting flags are covered. Formatting flags may be (un)set using member functions, but often manipulators having the same effect may also be used. For each of the flags it is shown how they can be controlled by a member function or -if available- a manipulator.

To display information in wide fields:

- `ios::internal`:

  > to add fill characters (blanks by default) between the minus sign of negative numbers and the value itself. Other values and data types are right-adjusted. Manipulator: `std::internal`. Example:

  >     cout.setf(ios::internal, ios::adjustfield);
  >     cout << internal;       // same, using the manipulator

  >     cout << '\'' << setw(5) << -5 << "'\n";  // displays '-   5'

- `ios::left`:
  to left-adjust values in fields that are wider than needed to display the values. Manipulator: `std::left`. Example:

      cout.setf(ios::left, ios::adjustfield);
      cout << left;           // same, using the manipulator

      cout << '\'' << setw(5) << "hi" << "'\n";  // displays 'hi   '

- `ios::right`:
  to right-adjust values in fields that are wider than needed to display the values. Manipulator: `std::right`. This is the default. Example:

      cout.setf(ios::right, ios::adjustfield);
      cout << right;          // same, using the manipulator

      cout << '\'' << setw(5) << "hi" << "'\n";  // displays '   hi'

Using various number representations:

- `ios::dec`:
  to display integral values as decimal numbers. Manipulator: `std::dec`. This is the default. Example:

      cout.setf(ios::dec, ios::basefield);
      cout << dec;            // same, using the manipulator
      cout << 0x10;           // displays 16

- `ios::hex`:
  to display integral values as hexadecimal numbers. Manipulator: `std::hex`. Example:

      cout.setf(ios::hex, ios::basefield);
      cout << hex;            // same, using the manipulator
      cout << 16;             // displays 10

- `ios::oct`:
  to display integral values as octal numbers. Manipulator: `std::oct`. Example:

      cout.setf(ios::oct, ios::basefield);
      cout << oct;            // same, using the manipulator
      cout << 16;             // displays 20

- `std::setbase(int radix)`:
  This is a manipulator that can be used to change the number representation to decimal, hexadecimal or octal. Example:

      cout << setbase(8);     // octal numbers, use 10 for
                              // decimal, 16 for hexadecimal
      cout << 16;             // displays 20

Fine-tuning displaying values:

- `ios::boolalpha`:
  logical values may be displayed as text using the text ``true`' for the `true` logical value, and ``false`' for the `false` logical value using `boolalpha`. By default this flag is not set. Complementary flag: `ios::noboolalpha`. Manipulators: `std::boolalpha` and `std::noboolalpha`. Example:

      cout.setf(ios::boolalpha);
      cout << boolalpha;      // same, using the manipulator
      cout << (1 == 1);       // displays true

- `ios::showbase`:
  to display the numeric base of integral values. With hexadecimal values the `0x` prefix is used, with octal values the prefix `0`. For the (default) decimal value no particular prefix is used. Complementary flag: `ios::noshowbase`. Manipulators: `std::showbase` and `std::noshowbase`. Example:

      cout.setf(ios::showbase);
      cout << showbase;       // same, using the manipulator
      cout << hex << 16;      // displays 0x10

- `ios::showpos`:
  to display the `+` sign with positive decimal (only) values. Complementary flag:
  `ios::noshowpos`. Manipulators: `std::showpos` and `std::noshowpos`. Example:

      cout.setf(ios::showpos);
      cout << showpos;            // same, using the manipulator
      cout << 16;                 // displays +16
      cout.unsetf(ios::showpos);  // Undo showpos
      cout << 16;                 // displays 16

- `ios::uppercase`:
  to display letters in hexadecimal values using capital letters. Complementary flag: `ios::nouppercase`. Manipulators: `std::uppercase` and `std::nouppercase`. By default lower case letters are used. Example:

      cout.setf(ios::uppercase);
      cout << uppercase;            // same, using the manipulator
      cout << hex << showbase <<
              3735928559;           // displays 0XDEADBEEF

Displaying floating point numbers

- `ios::fixed`:

  > to display real values using a fixed decimal point (e.g., 12.25 rather than 1.225e+01), the `fixed` formatting flag is used. It can be used to set a fixed number of digits behind the decimal point. Manipulator: `fixed`. Example:

  >     cout.setf(ios::fixed, ios::floatfield);
  >     cout.precision(3);          // 3 digits behind the .

  >         // Alternatively:
  >     cout << setiosflags(ios::fixed) << setprecision(3);

  >     cout << 3.0 << " " << 3.01 << " " << 3.001 << '\n';
  >          << 3.0004 << " " << 3.0005 << " " << 3.0006 << '\n'
  >         // Results in:
  >         // 3.000 3.010 3.001
  >         // 3.000 3.001 3.001

  > The example shows that 3.0005 is rounded away from zero, becoming 3.001 (likewise -3.0005 becomes -3.001). First setting precision and then `fixed` has the same effect.

- `ios::scientific`:
  to display real values in scientific notation (e.g., 1.24e+03). Manipulator: `std::scientific`. Example:

      cout.setf(ios::scientific, ios::floatfield);
      cout << scientific;         // same, using the manipulator
      cout << 12.25;              // displays 1.22500e+01

- `ios::showpoint`:
  to display a trailing decimal point and trailing decimal zeros when real numbers are displayed. Complementary flag: `ios::noshowpoint`. Manipulators: `std::showpoint`, `std::noshowpoint`. Example:

      cout << fixed << setprecision(3);   // 3 digits behind .

      cout.setf(ios::showpoint);      // set the flag
      cout << showpoint;              // same, using the manipulator

      cout << 16.0 << ", " << 16.1 << ", " << 16;
      // displays: 16.000, 16.100, 16

  Note that the final 16 is an integral rather than a floating point number, so it has no decimal point. So `showpoint` has no effect. If `ios::showpoint` is not active trailing zeros are discarded. If the fraction is zero the decimal point is discarded as well. Example:

      cout.unsetf(ios::fixed, ios::showpoint);    // unset the flags

      cout << 16.0 << ", " << 16.1;
      // displays: 16, 16.1

Handling whitespace and flushing streams

- `std::endl`:
  manipulator inserting a newline character and flushing the stream. Often flushing the stream is not required and doing so would needlessly slow down I/O processing. Consequently, using `endl` should be avoided (in favor of inserting `'\n'`) unless flushing the stream is explicitly intended. Note that streams are automatically flushed when the program terminates or when a stream is `tied' to another stream (cf. `tie` in section 6.3). Example:

      cout << "hello" << endl;    // prefer: << '\n';

- `std::ends`:
  manipulator inserting a 0-byte into a stream. It is usually used in combination with memory-streams (cf. section 6.4.3).

- `std::flush`:
  a stream may be flushed using this member. Often flushing the stream is not required and doing so would needlessly slow down I/O processing. Consequently, using `flush` should be avoided unless it is explicitly required to do so. Note that streams are automatically flushed when the program terminates or when a stream is `tied' to another stream (cf. `tie` in section 6.3). Example:

      cout << "hello" << flush;    // avoid if possible.

- `ios::skipws`:
  leading whitespace characters (blanks, tabs, newlines, etc.) are skipped when a value is extracted from a stream. This is the default. If the flag is not set, leading whitespace characters are not skipped. Manipulator: `std::skipws`. Example:

      cin.setf(ios::skipws);  // to unset, use
                              //  cin.unsetf(ios::skipws)

      cin >> skipws;          // same, using the manipulator
      int value;
      cin >> value;           // skips initial blanks

- `ios::unitbuf`:
  the stream for which this flag is set flushes its buffer after every output operation Often flushing a stream is not required and doing so would needlessly slow down I/O processing. Consequently, setting `unitbuf` should be avoided unless flushing the stream is explicitly intended. Note that streams are automatically flushed when the program terminates or when a stream is `tied' to another stream (cf. `tie` in section 6.3). Complementary flag: `ios::nounitbuf`. Manipulators: `std::unitbuf`, `std::nounitbuf`. Example:

      cout.setf(ios::unitbuf);
      cout << unitbuf;            // same, using the manipulator

      cout.write("xyz", 3);       // flush follows write.

- `std::ws`:
  manipulator removing all whitespace characters (blanks, tabs, newlines, etc.) at the current file position. White space characters are removed if present even if the flag `ios::noskipws` has been set. Example (assume the input contains 4 blank characters followed by the character `X`):

      cin >> ws;      // skip whitespace
      cin.get();      // returns 'X'

#### 6.3.2.3: The std::quoted manipulator

The `std::quoted` manipulator can be used to extract or insert quoted strings from, c.q. into, streams. The manipulator can, e.g., be used to read the text in quoted strings from a comma-separated data file or to surround text by quotes when writing such files.

The `quoted` manipulator defines three parameters, the second and third parameters have default values.

When inserting a `quoted` manipulator into an `std::ostream` its first parameter is a `char const *`, a `std::string const &`, or a `std::string_view` object. It inserts its first argument, surrounded by quotes, into the `std::ostream`.

When extracting a `quoted` manipulator from an `std::istream` its first parameter is an `std::string &`. It extracts a quoted string from the `std::istream` and stores the extracted text without the surrounding quotes into its first argument.

The second and third arguments specify, respectively, the delimiter that is used surrounding the quoted string (by default a double quote (`"`)), and an escape character that can be prefixed to characters inside the quoted string: the escape character will be ignored and the next character will be used as-is.

The generic form of the `quoted` manipulator is:

    quoted(source-or-destination, char delim = '"', char escape = '\\')

Within the quoted text blanks are not skipped.

Example, executing `a.out < input`:

        int main()
        {
            cout << quoted("hello \"world\"") << '\n';

            string str = "hello 'world'";
            cout << quoted(str, '\'', '%') << '\n';

            cin >> quoted(str);         // 1
            cin.ignore(100, '\n');
            cout << "1: " << str << '\n';

            cin >> quoted(str, '\'');   // 2
            cin.ignore(100, '\n');
            cout << "2: " << str << '\n';
        }

        // input
        //    "hello \"world\""
        //    'hello \'world\''

        // output:
        // "hello \"world\""
        // 'hello %'world%''
        // 1: hello "world"
        // 2: hello 'world'

## 6.4: Output

In C++ output is primarily based on the `std::ostream` class. The `ostream` class defines the basic operators and members inserting information into streams: the insertion operator (<<), and special members like `write` writing unformatted information to streams.

The class `ostream` acts as base class for several other classes, all offering the functionality of the `ostream` class, but adding their own specialties. In the upcoming sections the following classes are discussed:

- The class `ostream`, offering the basic output facilities;
- The class `ofstream`, allowing us to write files (comparable to C's `fopen(filename, "w")`);
- The class `ostringstream`, allowing us to write information to memory (comparable to C's `sprintf` function).

### 6.4.1: Basic output: the class `ostream'

The class `ostream` defines basic output facilities. The `cout`, `clog` and `cerr` objects are all `ostream` objects. All facilities related to output as defined by the `ios` class are also available in the `ostream` class.

We may define `ostream` objects using the following ostream constructor:

- `std::ostream object(std::streambuf *sb)`:

  > this constructor creates an `ostream` object which is a wrapper around an existing `std::streambuf` object. It isn't possible to define a plain `ostream` object (e.g., using `std::ostream out;`) that can thereupon be used for insertions. When `cout` or its friends are used, we are actually using a predefined `ostream` object that has already been defined for us and interfaces to the standard output stream using a (also predefined) `streambuf` object handling the actual interfacing.

  > It is, however, possible to define an `ostream` object passing it a 0-pointer. Such an object cannot be used for insertions (i.e., it raises its `ios::bad` flag when something is inserted into it), but it may be given a `streambuf` later. Thus it may be preliminary constructed, suspending its use until an appropriate `streambuf` becomes available (see also section 14.8).

To define the `ostream` class in C++ sources, the `<ostream>` header file must be included. To use the predefined `ostream` objects (`std::cerr, std::cout` etc.) the `<iostream>` header file must be included.

#### 6.4.1.1: Writing to `ostream' objects

The class `ostream` supports both formatted and binary output.

The insertion operator (<<) is 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.

The insertion operator points to the `ostream` object to receive the information. 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.. Each operator returns the `ostream` object into which the information so far has been inserted, and can thus immediately be followed by the next insertion.

In addition to insertion operators `ostreams` also support `std::print`. It is called as

         std::ostream& os, std::format_string<Args...> fmt, Args&&... args

where `...` indicates that any number of arguments can be specified. However, since a `print`-like functionality is hardly ever required in C++ programs it's not covered in detail in the C++ Annotations. Refer to `cppreference.com` for details about `std::print`.

When binary files must be written, normally no text-formatting is used or required: an `int` value should be written as a series of raw 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& put(char c)`:
  to write 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& write(char const *buffer, int length)`:
  to write at most `length` bytes, stored in the `char const *buffer` to the `ostream` object. Bytes are written as they are stored in the buffer, no formatting is done whatsoever. Note that the first argument is a `char const *`: a type cast is required to write any other type. For example, to write an `int` as an unformatted series of byte-values use:

      int x;
      out.write(reinterpret_cast<char const *>(&x), sizeof(int));

  The bytes written by the above `write` call are written to the `ostream` in an order depending on the endian-ness of the underlying hardware. Big-endian computers write the most significant byte(s) of multi-byte values first, little-endian computers first write the least significant byte(s).

#### 6.4.1.2: `ostream' positioning

Although not every `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 at random.

The current position can be obtained and modified using the following members:

- `ios::pos_type tellp()`:
  the current (absolute) position in the file where the next write-operation to the stream will take place is returned.
- `ostream &seekp(ios::off_type step, ios::seekdir org)`:
  modifies a stream's actual position. The function expects an `off_type` `step` representing the number of bytes the current stream position is moved with respect to `org`. The `step` value may be negative, zero or positive.

  The origin of the step, `org` is a value in the `ios::seekdir` enumeration. Its values are:

  - `ios::beg`:
    the stepsize is computed relative to the beginning of the stream. This value is used by default.

  - `ios::cur`:
    the stepsize is computed relative to the current position of the stream (as returned by `tellp`).

  - `ios::end`:
    the stepsize is interpreted relative to the current end position of the stream.
  It is OK to seek or write beyond the last file position. Writing bytes to a location beyond `EOF` will pad the intermediate bytes with 0-valued bytes: null-bytes. Seeking before `ios::beg` raises the `ios::fail` flag.

  Different from `seekg` (cf. section 6.5.1.2) `seekp` does not clear the stream's `ios::eofbit`. To reset an `ostream's` state to `good', its `clear` member should be called.

#### 6.4.1.3: `ostream' flushing

Unless the `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 during the write-operations, and when full it is flushed.

The stream's internal buffer can be flushed under program control:

- `ostream& flush()`:
  any buffered information stored internally by the `ostream` object is flushed to the device to which the `ostream` object interfaces. A stream is flushed automatically when:
  - the object ceases to exist;
  - the `endl` or `flush` manipulators (see section 6.3.2.2) are inserted into an `ostream` object;
  - a stream supporting the `close`-operation is explicitly closed (e.g., a `std::ofstream` object, cf. section 6.4.2).

### 6.4.2: Output to files: the class `ofstream'

The `std::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 `<fstream>` header file must be included. Including `fstream` does not automatically make available the standard streams `cin`, `cout` and `cerr`. Include `iostream` to declare these standard streams.

The following constructors are available for `ofstream` objects:

- `ofstream object`:

  > this is the basic constructor. It defines an `ofstream` object which may be associated with an actual file later, using its `open()` member (see below).

- `ofstream object(char const *name, ios::openmode mode = ios::out)`:

  > this constructor defines an `ofstream` object and associates it immediately with the file named `name` using output mode `mode`. Section 6.4.2.1 provides an overview of available output modes. Example:

  >     ofstream out("/tmp/scratch");

It is not possible to open an `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 `std::streambuf` object (and in some implementations: with a `std::filebuf` object, which is also a `streambuf`). `Streambuf` objects are discussed in section 14.8, `filebuf` objects are discussed in section 14.8.3.

Instead of directly associating an `ofstream` object with a file, the object can be constructed first, and opened later.

- `void open(char const *name, ios::openmode mode = ios::out)`:
  associates an `ofstream` object with an actual file. If the `ios::fail` flag was set before calling `open` and opening succeeds the flag is cleared. Opening an already open stream fails. To reassociate a stream with another file it must first be closed:

      ofstream out("/tmp/out");
      out << "hello\n";
      out.close();        // flushes and closes out
      out.open("/tmp/out2");
      out << "world\n";

- `void close()`:
  closes the `ofstream` object. The function sets the `ios::fail` flag of the closed object. Closing the file flushes any buffered information to the associated file. A file is automatically closed when the associated `ofstream` object ceases to exist.

- `bool is_open() const`:
  assume a stream was properly constructed, but it has not yet been attached to a file. E.g., the statement `ofstream ostr` was executed. When we now check its status through `good()`, a non-zero (i.e., OK) value is returned. The `good' status here indicates that the stream object has been constructed properly. It doesn't mean the file is also open. To test whether a stream is actually open, `is_open` should be called. If it returns `true`, the stream is open. Example:

          #include <fstream>
          #include <iostream>

          using namespace std;

          int main()
          {
              ofstream of;

              cout << "of's open state: " << boolalpha << of.is_open() << '\n';

              of.open("/dev/null");       // on Unix systems

              cout << "of's open state: " << of.is_open() << '\n';
          }
          /*
              Generated output:
          of's open state: false
          of's open state: true
          */

#### 6.4.2.1: Modes for opening stream objects

The following file modes or file flags are available when constructing or opening `ofstream` (or `istream`, see section 6.5.2) objects. The values are of type `ios::openmode`. Flags may be combined using the `bitor` operator.

- `ios::app`:
  reposition the stream to its end before every output command (see also `ios::ate` below). The file is created if it doesn't yet exist. When opening a stream in this mode any existing content of the file is kept.
- `ios::ate`:
  start initially at the end of the file. Note that any existing content is only kept if some other flag tells the object to do so. For example `ofstream out("gone", ios::ate)` rewrites the file `gone`, because the implied `ios::out` causes the rewriting. If rewriting of an existing file should be prevented, the `ios::in` mode should be specified too. However, when `ios::in` is specified the file must already exist. The `ate` mode only initially positions the file at the end of file position. After that information may be written in the middle of the file using `seekp`. When the `app` mode is used information is only written at end of file (effectively ignoring `seekp` operations).
- `ios::binary`:
  open a file in binary mode (used on systems distinguishing text- and binary files, like MS-Windows).

- `ios::in`:
  open the file for reading. The file must exist.
- `ios::out`:
  open the file for writing. 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 content of the file is lost.

The following combinations of file flags have special meanings:

    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.

An interesting subtlety is that the `open` members of the `ifstream, ofstream` and `fstream` classes have a second parameter of type `ios::openmode`. In contrast to this, the `bitor` operator returns an `int` when applied to two enum-values. The question why the `bitor` operator may nevertheless be used here is answered in a later chapter (cf. section 11.13).

### 6.4.3: Output to memory: the class `ostringstream'

To write information to memory using `stream` facilities, `std::ostringstream` objects should be used. As the class `ostringstream` is derived from the class `ostream` all `ostream`'s facilities are available to `ostringstream` objects as well. To use and define `ostringstream` objects the header file `<sstream>` must be included. In addition the class `ostringstream` offers the following constructors and members:

- `ostringstream ostr(string const &init, ios::openmode mode = ios::out)`:
  when specifying `openmode` as `ios::ate`, the `ostringstream` object is initialized by the `string init` and remaining insertions are appended to the content of the `ostringstream` object.

- `ostringstream ostr(ios::openmode mode = ios::out)`:
  this constructor can also be used as default constructor. Alternatively it allows, e.g., forced additions at the end of the information stored in the object so far (using `ios::app`). Example:

      std::ostringstream out;

- `std::string str() const`:
  a copy of the string that is stored inside the `ostringstream` object is returned.
- `void str(std::string const &str)`:
  the current object is reinitialized with new initial content.

The following example illustrates the use of the `ostringstream` class: several values are inserted into the object. Then, the text contained by the `ostringstream` object is stored in a `std::string`, whose length and content are thereupon printed. Such `ostringstream` objects are most often used for doing `type to string' conversions, like converting `int` values to text. Formatting flags can be used with `ostringstreams` as well, as they are part of the `ostream` class.

Here is an example showing an `ostringstream` object being used:

        #include <iostream>
        #include <sstream>

        using namespace std;

        int main()
        {
            ostringstream ostr("hello ", ios::ate);

            cout << ostr.str() << '\n';

            ostr.setf(ios::showbase);
            ostr.setf(ios::hex, ios::basefield);
            ostr << 12345;

            cout << ostr.str() << '\n';

            ostr << " -- ";
            ostr.unsetf(ios::hex);
            ostr << 12;

            cout << ostr.str() << '\n';

            ostr.str("new text");
            cout << ostr.str() << '\n';

            ostr.seekp(4, ios::beg);
            ostr << "world";
            cout << ostr.str() << '\n';
        }
        /*
            Output from this program:
        hello
        hello 0x3039
        hello 0x3039 -- 12
        new text
        new world
        */

### 6.4.4: The `put_time' manipulator

The manipulator `std::put_time(std::tm const *specs, char const *fmt)` can be used to insert time specifications into `std::ostream` objects. Before using `put_time` the `<iomanip>` header must be included.

Time specifications are provided in `std::tm` objects, and the way the time should be displayed is defined by the format string `fmt`.

Starting with a `chrono::time_point` the following steps must be performed to insert the time point's time into a `std::ostream`:

- Obtain a `time_point` (e.g.: `system_clock{}.now()`);

- Pass the time point to the clock's `to_time_t` function, saving the returned `time_t` value:

      time_t secs = system_clock::to_time_t( system_clock{}.now() );

- Pass `sec's` address to either `std::localtime` or `std::gmtime`. These functions return `std::tm` structs containing the required time components expressed in, respectively, the computer's local time or GMT;

- Pass the return value of either `localtime` or `gmtime` together with a format string (e.g., `"%c"`) to `put_time`, inserting it into an `std::ostream`:

                      // displays, e.g., Mon Nov  4 21:34:59 2019
      time_t secs = system_clock::to_time_t( system_clock{}.now() );
      std::cout << std::put_time(std::localtime(&secs), "%c") << '\n';

A simple function returning `put_time's` return value and expecting a `time_point` and format string can be defined which handles the above two statements. E.g., (omitting the `std::` and `std::chrono::` specifications for brevity):

        auto localTime(time_point<system_clock> const &tp, char const *fmt)
        {
            time_t secs = system_clock::to_time_t( tp );
            return put_time(localtime(&secs), fmt);
        }
                    // used as:
        cout << localTime(system_clock{}.now(), "%c") << '\n';

Many more format specifiers are recognized by `put_time`. Specifiers start with `%`. To display a percent character as part of the format string write it twice: `%%`. In addition to the standard escape sequences, `%n` can be used instead of `\n`, and `%t` can be used instead of `\t`.

Year specifiers
Specifier |  | Meaning |  | std::tm field(s)

%Y |  | year as a 4 digit decimal number |  | tm_year
%EY |  | year in an alternative representation |  | tm_year
%y |  | last 2 digits of year as a decimal number (range [00,99]) |  | tm_year
%Oy |  | last 2 digits of year using an alternative numeric system |  | tm_year
%Ey |  | year as offset from locale's alternative calendar period %EC (locale-dependent) |  | tm_year
%C |  | first 2 digits of year as a decimal number (range [00,99]) |  | tm_year
%EC |  | name of the base year (period) in the locale's alternative representation |  | tm_year
%G |  | ISO 8601 week-based year, i.e. the year that contains the specified week |  | tm_year, tm_wday, tm_yday
%g |  | last 2 digits of ISO 8601 week-based year (range [00,99]) |  | tm_year, tm_wday, tm_yday

Month specifiers
Specifier |  | Meaning |  | std::tm field(s)

%b |  | abbreviated month name, e.g. Oct |  | tm_mon
%m |  | month as a decimal number (range [01,12]) |  | tm_mon
%Om |  | month using an alternative numeric system |  | tm_mon

Week specifiers
Specifier |  | Meaning |  | std::tm field(s)

%U |  | week of the year as a decimal number (Sunday is the first day of the week) (range [00,53]) |  | tm_year, tm_wday, tm_yday
%OU |  | week of the year, as by %U, using an alternative numeric system |  | tm_year, tm_wday, tm_yday
%W |  | week of the year as a decimal number (Monday is the first day of the week) (range [00,53]) |  | tm_year, tm_wday, tm_yday
%OW |  | week of the year, as by %W, using an alternative numeric system |  | tm_year, tm_wday, tm_yday
%V |  | ISO 8601 week of the year (range [01,53]) |  | tm_year, tm_wday, tm_yday
%OV |  | week of the year, as by %V, using an alternative numeric system |  | tm_year, tm_wday, tm_yday

Day of the year/month specifiers
Specifier |  | Meaning |  | std::tm field(s)

%j |  | day of the year as a decimal number (range [001,366]) |  | tm_yday
%d |  | day of the month as a decimal number (range [01,31]) |  | tm_mday
%Od |  | zero-based day of the month using an alternative numeric system |  | tm_mday
%e |  | day of the month as a decimal number (range [1,31]) |  | tm_mday
%Oe |  | one-based day of the month using an alternative numeric system |  | tm_mday

Day of the week specifiers
Specifier |  | Meaning |  | std::tm field(s)

%a |  | abbreviated weekday name, e.g. Fri |  | tm_wday
%A |  | full weekday name, e.g. Friday |  | tm_wday
%w |  | weekday as a decimal number, where Sunday is 0 (range [0-6]) |  | tm_wday
%Ow |  | weekday, where Sunday is 0, using an alternative numeric system |  | tm_wday
%u |  | weekday as a decimal number, where Monday is 1 (ISO 8601 format) (range [1-7]) |  | tm_wday
%Ou |  | weekday, where Monday is 1, using an alternative numeric system |  | tm_wday

Hour, minute, second specifiers
Specifier |  | Meaning |  | std::tm field(s)

%H |  | hour as a decimal number, 24 hour clock (range [00-23]) |  | tm_hour
%OH |  | hour from 24-hour clock using an alternative numeric system |  | tm_hour
%I |  | hour as a decimal number, 12 hour clock (range [01,12]) |  | tm_hour
%OI |  | hour from 12-hour clock using the alternative numeric system |  | tm_hour
%M |  | minute as a decimal number (range [00,59]) |  | tm_min
%OM |  | minute using an alternative numeric system |  | tm_min
%S |  | second as a decimal number (range [00,60]) |  | tm_sec
%OS |  | second using an alternative numeric system |  | tm_sec

Additional specifiers
Specifier |  | Meaning |  | std::tm field(s)

%c |  | standard date and time string, e.g. Sun Oct 17 04:41:13 2010 |  | all
%Ec |  | alternative date and time string |  | all
%x |  | localized date representation |  | all
%Ex |  | alternative date representation |  | all
%X |  | localized time representation |  | all
%EX |  | alternative time representation |  | all
%D |  | equivalent to `"%m/%d/%y"` |  | tm_mon, tm_mday, tm_year
%F |  | equivalent to `"%Y-%m-%d"` (the ISO 8601 date format) |  | tm_mon, tm_mday, tm_year
%r |  | localized 12-hour clock time |  | tm_hour, tm_min, tm_sec
%R |  | equivalent to `"%H:%M"` |  | tm_hour, tm_min
%T |  | equivalent to `"%H:%M:%S"` (the ISO 8601 time format) |  | tm_hour, tm_min, tm_sec
%p |  | localized a.m. or p.m. |  | tm_hour
%z |  | offset from UTC in the ISO 8601 format (e.g. -0430; no characters if time zone information is not available) |  | tm_isdst
%Z |  | time zone name or abbreviation (no characters if time zone information is not available) |  | tm_isdst

## 6.5: Input

In C++ input is primarily based on the `std::istream` class. The `istream` class defines the basic operators and members extracting information from streams: the extraction operator (>>), and special members like `istream::read` reading unformatted information from streams.

The class `istream` acts as base class for several other classes, all offering the functionality of the `istream` class, but adding their own specialties. In the upcoming sections the following classes are discussed:

- The class `istream`, offering the basic facilities for doing input;
- The class `ifstream`, allowing us to read files (comparable to C's `fopen(filename, "r")`);
- The class `istringstream`, allowing us to extract information from memory rather than from file (comparable to C's `sscanf` function).

### 6.5.1: Basic input: the class `istream'

The class `istream` defines basic input facilities. The `cin` object, is an `istream` object. All facilities related to input as defined by the `ios` class are also available in the `istream` class.

We may define `istream` objects using the following istream constructor:

- `istream object(streambuf *sb)`:

  > this constructor can be used to construct a wrapper around an existing `std::streambuf` object. Similarly to `ostream` objects, `istream` objects may be defined by passing it initially a 0-pointer. See section 6.4.1 for a discussion, see also section 14.8, and see chapter 26 for examples.

To define the `istream` class in C++ sources, the `<istream>` header file must be included. To use the predefined `istream` object `cin`, the `<iostream>` header file must be included.

#### 6.5.1.1: Reading from `istream' objects

The class `istream` supports both formatted and unformatted (binary) input. The extraction operator (`operator>>`) is 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.

The extraction operator points to the objects or variables to 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 many (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 the location pointed at by a pointer, etc., etc.. String or character array extraction by default first skips all whitespace characters, and then extracts all consecutive non-whitespace 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 additional `istream` operations that appear in the same expression.

Streams do not support facilities for formatted input as offered by C's `scanf` and `vscanf` functions. Although it is not difficult to add such facilities to the world of streams, `scanf`-like functionality is in practice never needed in C++ programs. Furthermore, as it is potentially type-unsafe, it is better to avoid using C-type formatted input.

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 gcount() const`:
  the number of characters read from the input stream by the last unformatted input operation is returned.
- `int get()`:
  the next available single character is returned as an unsigned `char` value using an `int` return type. `EOF` is returned if no more character are available.
- `istream &get(char &ch)`:
  the next single character read from the input stream is stored in `ch`. The member function returns the stream itself which may be inspected to determine whether a character was obtained or not.
- `istream &get(char *buffer, int len, char delim = '\n')`:
  At most `len - 1` characters are read from the input stream into the array starting at `buffer`, which should be at least `len` bytes long. Reading also stops when the delimiter `delim` is encountered. However, the delimiter itself is not removed from the input stream.

  Having stored the characters into `buffer`, a 0-valued character is written beyond the last character stored into the `buffer`. The functions `eof` and `fail` (see section 6.3.1) return 0 (`false`) if the delimiter was encountered before reading `len - 1` characters or if the delimiter was not encountered after reading `len - 1` characters. It is OK to specifiy a 0-valued character delimiter: this way NTBSs may be read from a (binary) file.

- `istream &getline(char *buffer, int len, char delim = '\n')`:
  this member function operates analogously to the `get` member function, but `getline` removes `delim` from the stream if it is actually encountered. The delimiter itself, if encountered, is not stored in the `buffer`. If `delim` was not found (before reading `len - 1` characters) the `fail` member function, and possibly also `eof` returns true. Realize that the `std::string` class also offers a function `std::getline` which is generally preferred over this `getline` member function that is described here (see section 5.2.4).

- `istream &ignore()`:
  one character is skipped from the input stream.
- `istream &ignore(int n)`:
  `n` characters are skipped from the input stream.
- `istream &ignore(int n, int delim)`:
  at most `n` characters are skipped but skipping characters stops after having removed `delim` from the input stream.
- `int peek()`:
  this function returns the next available input character, but does not actually remove the character from the input stream. `EOF` is returned if no more characters are available.
- `istream &putback(char ch)`:
  The character `ch` is `pushed back' into the input stream, to be read again as the next available character. `EOF` is returned if this is not allowed. Normally, it is OK to put back one character. Example:

      string value;
      cin >> value;
      cin.putback('X');
                      // displays: X
      cout << static_cast<char>(cin.get());

- `istream &read(char *buffer, int len)`:
  At most `len` bytes are read from the input stream into the buffer. If `EOF` is encountered first, fewer bytes are read, with the member function `eof` returning `true`. This function is commonly used when reading binary files. Section 6.5.2 contains an example in which this member function is used. The member function `gcount()` may be used to determine the number of characters that were retrieved by `read`.

- `istream &readsome(char *buffer, int len)`:
  at most `len` bytes are read from the input stream into the buffer. All available characters are read into the buffer, but if `EOF` is encountered, fewer bytes are read, without setting the `ios::eofbit` or `ios::failbit`.

- `istream &unget()`:
  the last character that was read from the stream is put back.

#### 6.5.1.2: `istream' positioning

Although not every `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 current position can be obtained and modified using the following members:

- `ios::pos_type tellg()`:
  the stream's current (absolute) position where the stream's next read-operation will take place is returned.
- `istream &seekg(ios::off_type step, ios::seekdir org)`:
  modifies a stream's actual position. The function expects an `off_type` `step` representing the number of bytes the current stream position is moved with respect to `org`. The `step` value may be negative, zero or positive.

  The origin of the step, `org` is a value in the `ios::seekdir` enumeration. Its values are:

  - `ios::beg`:
    the stepsize is computed relative to the beginning of the stream. This value is used by default.

  - `ios::cur`:
    the stepsize is computed relative to the current position of the stream (as returned by `tellp`).

  - `ios::end`:
    the stepsize is interpreted relative to the current end position of the stream.
  It is OK to seek beyond the last file position. Seeking before `ios::beg` raises the `ios::failbit` flag.

  Calling `seekg` clears the `istream's ios::failbit`, but not its `ios::badbit` or `ios::badbit`. To ensure that the stream's state is reset to `good' its member `clear` should be called.

  To illustrate: in the following example `cin's ios::eofbit` is set. Following `seekg` that bit is cleared, but its `ios::goodbit` stil isn't set. Since its `goodbit` isn't set, extraction fails following `seekg`:

          int main()                  // in 'src.cc'
          {
              cin.setstate(ios::eofbit | ios::failbit);
              cerr << cin.good() << ' ' << cin.eof() << '\n';

              cin.seekg(0);
              cerr << cin.good() << ' ' << cin.eof() << '\n' <<
                      (cin.get() == EOF ? "failed" : "OK") << '\n';

              cin.clear();
              cerr << cin.good() << ' ' << cin.eof() << '\n' <<
                      (cin.get() == EOF ? "failed" : "OK") << '\n';
          }
          outputs when called as 'a.out < src.cc':
              0 1
              0 0
              failed
              1 0
              OK

### 6.5.2: Input from files: the class `ifstream'

The `std::ifstream` class is derived from the `istream` class: it has the same capabilities as the `istream` class, but can be used to access files for reading.

In order to use the `ifstream` class in C++ sources, the `<fstream>` header file must be included. Including `fstream` does not automatically make available the standard streams `cin`, `cout` and `cerr`. Include `iostream` to declare these standard streams.

The following constructors are available for `ifstream` objects:

- `ifstream object`:

  > this is the basic constructor. It defines an `ifstream` object which may be associated with an actual file later, using its `open()` member (see below).

- `ifstream object(char const *name, ios::openmode mode = ios::in)`:

  > this constructor can be used to define an `ifstream` object and associate it immediately with the file named `name` using input mode `mode`. Section 6.4.2.1 provides an overview of available input modes. Example:

  >     ifstream in("/tmp/input");

Instead of directly associating an `ifstream` object with a file, the object can be constructed first, and opened later.

- `void open(char const *name, ios::openmode mode = ios::in)`:
  associates an `ifstream` object with an actual file. If the `ios::fail` flag was set before calling `open` and opening succeeds the flag is cleared. Opening an already open stream fails. To reassociate a stream with another file it must first be closed:

      ifstream in("/tmp/in");
      in >> variable;
      in.close();        // closes in
      in.open("/tmp/in2");
      in >> anotherVariable;

- `void close()`:
  closes the `ifstream` object. The function sets the `ios::fail` flag of the closed object. Closing the file flushes any buffered information to the associated file. A file is automatically closed when the associated `ifstream` object ceases to exist.

- `bool is_open() const`:
  assume a stream was properly constructed, but it has not yet been attached to a file. E.g., the statement `ifstream ostr` was executed. When we now check its status through `good()`, a non-zero (i.e., OK) value is returned. The `good' status here indicates that the stream object has been constructed properly. It doesn't mean the file is also open. To test whether a stream is actually open, `is_open` should be called. If it returns `true`, the stream is open. Also see the example in section 6.4.2. The following example illustrates reading from a binary file (see also section 6.5.1.1):

          #include <fstream>
          using namespace std;

          int main(int argc, char **argv)
          {
              ifstream in(argv[1]);
              double   value;

              // reads double in raw, binary form from file.
              in.read(reinterpret_cast<char *>(&value), sizeof(double));
          }

### 6.5.3: Input from memory: the class `istringstream'

To read information from memory using `stream` facilities, `std::istringstream` objects should be used. As the class `istringstream` is derived from the class `istream` all `istream`'s facilities are available to `istringstream` objects as well. To use and define `istringstream` objects the header file `<sstream>` must be included. In addition the class `istringstream` offers the following constructors and members:

- `istringstream istr(string const &init, ios::openmode mode = ios::in)`:
  the object is initialized with `init`'s content
- `istringstream istr(ios::openmode mode = ios::in)`:
  this constructor is usually used as the default constructor. Example:

      std::istringstream in;

- `void str(std::string const &str)`:
  the current object is reinitialized with new initial content.

The following example illustrates the use of the `istringstream` class: several values are extracted from the object. Such `istringstream` objects are most often used for doing `string to type' conversions, like converting text to `int` values (cf. C's `atoi` function). Formatting flags can be used with `istringstreams` as well, as they are part of the `istream` class. In the example note especially the use of the member `seekg`:

        #include <iostream>
        #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 << '\n';          // write it out
            istr.seekg(0);              // retry from the beginning
            istr >> x;                  // extract int
            cout << x << '\n';          // write it out
            istr.str("666");            // store another text
            istr >> x;                  // extract it
            cout << x << '\n';          // write it out
        }
        /*
            output of this program:
        3
        123
        666
        */

### 6.5.4: Copying streams

Usually, files are copied either by reading a source file character by character or line by line. The basic mold to process streams is as follows:

- Continuous loop:
  1. read from the stream
  2. if reading did not succeed (i.e., `fail` returns `true`), `break` from the loop
  3. process the information that was read

Note that reading must precede testing, as it is only possible to know after actually attempting to read from a file whether the reading succeeded or not. Of course, variations are possible: `getline(istream &, string &)` (see section 6.5.1.1) returns an `istream &`, so here reading and testing may be contracted using one expression. Nevertheless, the above mold represents the general case. So, the following program may 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;
        }
    }

Contraction is possible here by combining `get` with the `if`-statement, resulting in:

        if (!cin.get(c))
            break;

Even so, this would still follow the basic rule: `read first, test later'.

Simply copying a file isn't required very often. More often a situation is encountered where a file is processed up to a certain point, followed by plain copying the file's remaining information. The next program illustrates this. Using `ignore` 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 yet another overloaded version of the <<-operator, in which a `streambuf` pointer is inserted into a stream. As the member `rdbuf` returns a stream's `streambuf *`, we have a simple means of inserting a stream's content into an `ostream`:

        #include <iostream>
        using namespace std;

        int main()
        {
            cin.ignore(80, '\n');   // skip the first line and...
            cout << cin.rdbuf();    // copy the rest through the streambuf *
        }

This way of copying streams only assumes the existence of a `streambuf` object. Consequently it can be used with all specializations of the `streambuf` class.

### 6.5.5: Coupling streams

Ostream objects can be coupled to `ios` objects using the `tie` member function. Tying results in flushing the `ostream`'s buffer 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` (using `cin.tie(cout)`). This tie means that whenever an operation on `cin` is requested, `cout` is flushed first. To break the tie, `ios::tie(0)` can be called. In the example: `cin.tie(0)`.

Another useful coupling of streams is shown by the tie between `cerr` and `cout`. Because of the tie standard output and error messages written to the screen are shown in sync with the time at which they were generated:

        #include <iostream>
        using namespace std;

        int main()
        {
            cerr.tie(0);        // untie
            cout << "first (buffered) line to cout ";
            cerr << "first (unbuffered) line to cerr\n";
            cout << "\n";

            cerr.tie(&cout);    // tie cout to cerr
            cout << "second (buffered) line to cout ";
            cerr << "second (unbuffered) line to cerr\n";
            cout << "\n";
        }
        /*
            Generated output:

            first (unbuffered) line to cerr
            first (buffered) line to cout
            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 stream library rather than operating system calls can be implemented. See the next sections for examples.

## 6.6: Advanced topics

### 6.6.1: Moving streams

Stream classes (e.g.,, all stream classes covered in this chapter) are movable and can be swapped. This implies that factory functions can be designed for stream classes. Here is an example:

        ofstream out(string const &name)
        {
            ofstream ret(name);             // construct ofstream
            return ret;                     // return value optimization, but
        }                                   // OK as moving is supported

        int main()
        {
            ofstream mine(out("out"));      // return value optimizations, but
                                            // OK as moving is supported

            ofstream base("base");
            ofstream other;

            base.swap(other);               // swapping streams is OK

            other = std::move(base);        // moving streams is OK

            // other = base;                // this would fail: copy assignment
                                            // is not available for streams
        }

### 6.6.2: Redirecting streams

Using `ios::rdbuf` streams can be forced to share their `streambuf` objects. Thus information written to one stream is actually written to another stream; a phenomenon normally called redirection. Redirection is commonly implemented at the operating system level, and sometimes that is still necessary (see section 26.2.3).

A common situation where redirection is useful is when error messages should be written to file rather than to the standard error stream, usually indicated by its file descriptor number 2. In the Unix operating system using the `bash` shell, this can be realized as follows:

        program 2>/tmp/error.log

Following this command any error messages written by `program` are written to `/tmp/error.log`, instead of appearing on the screen.

Here is an example showing how this can be implemented using `streambuf` objects. Assume `program` expects an argument defining the name of the file to write the error messages to. It could be called as follows:

        program /tmp/error.log

The program looks like this, an explanation is provided below the program's source text:

        #include <iostream>
        #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
        */

- At lines 1-2 local variables are defined: `errlog` is the `ofstream` to write the error messages to, and `cerr_buffer` is a pointer to a `streambuf`, to point to the original `cerr` buffer.
- At line 3 the alternate error stream is opened.
- At line 4 redirection takes place: `cerr` now writes to the `streambuf` defined by `errlog`. It is important that the original buffer used by `cerr` is saved, as explained below.
- At line 5 we pause. At this point, two lines were written to the alternate error file. We get a chance to take a look at its content: there were indeed two lines written to the file.
- At line 6 the redirection is terminated. This is very important, as the `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.
- Finally, at line 7, `Done` is again written to the screen, as the redirection has been terminated.

### 6.6.3: Reading AND Writing streams

Streams can be read and written using `std::iostream` objects. Commonly encountered are `std::fstream` objects and sometimes `std::stringstream` objects. Other types of readable and writable streams can be defined, by deriving such streams from the `std::iostream` class (cf. chapter 14, in particular its section 14.8.2).

In this section we concentrate on the `std::fstream` class. As with `ifstream` and `ofstream` objects, the `fstream` constructor expects the name of the file to be opened:

            fstream inout("iofile", ios::in | ios::out);

Note the use of the 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 `bitor` operator. Alternatively, instead of `ios::out`, `ios::app` could have been used and mere writing would become appending (at the end of the file).

Reading and writing to the same stream is always a bit awkward: what to do when the stream may not yet exist, but if it already exists it should not be rewritten? To realize this the following approach can be used:

        #include <fstream>
        #include <iostream>
        #include <string>

        using namespace std;

        int main()
        {
            fstream rw("fname", ios::out | ios::in);

            if (!rw)            // file didn't exist yet
            {
                rw.clear();     // try again, creating it using ios::trunc
                rw.open("fname", ios::out | ios::trunc | ios::in);
            }

            if (!rw)            // can't even create it: bail out
            {
                cerr << "Opening `fname' failed miserably" << '\n';
                return 1;
            }

            cerr << "We're at: " << rw.tellp() << '\n';

                                // write something
            rw << "Hello world" << '\n';

            rw.seekg(0);        // go back and read what's written

            string s;
            getline(rw, s);

            cout << "Read: " << s << '\n';
        }

Under this approach if the construction fails `fname` didn't yet exist. But then, after clearing the failure flag, `open` is used also specifying the `ios::trunc` flag: this creates an empty file, but because of `ios::in` the file is also readable. In addition `ios::ate` could be specified, ensuring that the initial read/write action would by default occur at `EOF`.

Under DOS-like operating systems that use the multiple character sequence `\r\n` to separate lines in text files the flag `ios::binary` is required to process binary files ensuring that `\r\n` combinations are processed as two characters. In general, `ios::binary` should be specified when binary (non-text) files are to be processed. By default files are opened as text files. Unix operating systems do not distinguish text files from binary files.

With `fstream` (in general: `iostream`) objects, combinations of file flags are used to make sure that a stream is or is not (re)created empty when opened. See section 6.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 seek operation is used to activate the stream's data used for reading or those used for writing (and vice versa). The `istream` and `ostream` parts of `fstream` objects share the stream's data buffer and by performing the seek operation the stream either activates its `istream` or its `ostream` part. If the seek is omitted, reading after writing and writing after reading simply fails. The example shows a whitespace-delimited word being read from a file, writing another string to the file, just beyond the point where the just read word terminated. Finally yet another string is read which is found just beyond the location where the just written strings ended:

        fstream f("filename", ios::in | ios::out);
        string  str;

        f >> str;       // read the first word

                        // write a well-known text
        f.seekp(0, ios::cur);
        f << "hello world";

        f.seekg(0, ios::cur);
        f >> str;       // and read again

Since a seek or clear operation is required when alternating between 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 occur at well-known locations in a file. In those cases, the position where insertions or extractions are required can be controlled and monitored by the `seekg`, `seekp, tellg` and `tellp` members (see sections 6.4.1.2 and 6.5.1.2).

Error conditions (see section 6.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 by 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 situation where files are both read and written is seen in database applications, using files consisting of records having fixed sizes, and where locations and sizes of pieces of information are known. For example, the following program adds text lines to a (possibly existing) file. It can also be used to retrieve a particular line, given its order-number in the file. A binary file `index` allows for the quick retrieval of the location of lines.

        #include <iostream>
        #include <fstream>
        #include <string>
        #include <climits>
        using namespace std;

        void err(char const *msg)
        {
            cout << msg << '\n';
        }

        void err(char const *msg, long value)
        {
            cout << msg << value << '\n';
        }

        void read(fstream &index, fstream &strings)
        {
            int idx;

            if (!(cin >> idx))                          // read index
            {
                cin.clear();                            // allow reading again
                cin.ignore(INT_MAX, '\n');              // skip the line
                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 offset ", offset);

            string line;

            if (!getline(strings, line))                // read the line
                return err("no line at ", offset);

            cout << "Got line: " << line << '\n';       // 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 << '\n'))           // write the line itself
                return err("Writing to `strings' failed");
                                                      // confirm writing the line
            cout << "Write at offset " << offset << " line: " << line << '\n';
        }

        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 if (cin.eof())
                {
                    cout << "\n"
                            "Unexpected end-of-file\n";
                    return 1;
                }
                else
                    cout << "Unknown command: " << cmd << '\n';
            }
        }

Another example showing reading and writing of files is provided by the next program. It also illustrates the processing of NTBSs:

        #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 NTB strings
            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() << '\n';
            f >> c;                             // read the NTB delim

                                                // and read the second `hello'
            cout << f.get(buffer + 6, sizeof(buffer) - 6, 0).tellg() << '\n';

            buffer[5] = ' ';                    // change asciiz to ' '
            cout << buffer << '\n';             // show 2 times `hello'
        }
        /*
            Generated output:
        5
        11
        hello hello
        */

A completely different way to read and write streams may be implemented using `streambuf` members. All considerations mentioned so far remain valid (e.g., before a read operation following a write operation `seekg` must be used). When `streambuf` objects are used, either an `istream` is associated with the `streambuf` object of another `ostream` object, or an `ostream` object is associated with the `streambuf` object of another `istream` object. Here is the previous program again, 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 << '\n';
            }
        }

In this example

- the streams associated with the `streambuf` objects of existing streams are not `ifstream` or `ofstream` objects but basic `istream` and `ostream` objects.
- The `streambuf` object is not defined by an `ifstream` or `ofstream` object. Instead it is defined outside of the streams, using a `filebuf` (cf. section 14.8.3) and constructions like:

      filebuf fb("index", ios::in | ios::out | ios::trunc);
      istream index_in(&fb);
      ostream index_out(&fb);

- An `ifstream` object can be constructed using stream modes normally used with `ofstream` objects. Conversely, an `ofstream` objects can be constructed using stream modes normally used with `ifstream` objects.
- If `istream` and `ostreams` share a `streambuf`, then their read and write pointers (should) point to the shared buffer: they are tightly coupled. However, instead of using two objects, defining/using a `iostream` object receiving the `streambuf` automatically ensures that positioning for reading and writing is synchronized (see also section 14.8.2).
- The advantage of using an external (separate) `streambuf` used by an `iostream` object over using a predefined `fstream` object is that the stream doesn't have to be a named file (see also section 14.8).

Like `fstream` objects string-stream objects can also be used for reading and writing. After including the `<sstream>` header file a `std::stringstream` can be defined which supports both reading and writing. After inserting information into a `stringstream` object `seekg(0)` can be called to read its info from the beginning of its content. When a `stringstream` must repeatedly be used for reading and writing call its `clear` and `str` members before starting a new writing cycle. Alternatively, a `stringstream str` can be reinitialized using `str = stringstream{}`. Here is an example:

        #include <iostream>
        #include <sstream>
        using namespace std;

        int main(int argc, char **argv)
        {
            stringstream io;
            for (size_t redo = 0; redo != 2; ++redo)
            {
                io.clear();                 // clears the not-good flags
                io.str("");
                io << argv[0] << '\n';

                io.seekg(0);
                string line;
                while (getline(io, line))   // results in io.eof()
                    cout << line << '\n';
            }
        }

- Table of Contents
- Previous Chapter
- Next Chapter