9.2 Text I/O

By default, an I/O stream performs text I/O, also known as formatted I/O, in which text is converted to and from numeric and other values. For output, values are converted to text, and padding, alignment, and other formatting is applied to the text. For input, formatting controls how text is converted to values and whether whitespace is skipped prior to reading an input field.

figs/acorn.gif

Different systems have different ways of representing the end of a line. A text I/O stream hides these details and maps all line endings in a file to the newline character ('\n'). Thus, the number of characters read from or written to a file might not match the actual file size. An implementation might require a newline at the end of the last line of a file.

To control formatting, a stream keeps track of a set of flags, a field width, and a precision. Table 13-12 (in the <ios> section) lists all the formatting flags.

9.2.1 Formatted Input

The formatted input functions are the overloaded operator>> functions. If the skipws flag is set (which is the default), whitespace characters (according to the locale imbued in the stream) are skipped, and input begins with the first non-whitespace character.

If reading into a string or character array, all non-whitespace characters are read into the string, ending with the first whitespace character or when width characters have been read (if width > 0), whichever comes first. The width is then reset to 0.

For all other types, the width is not used. To read a number from a fixed-width field, read the field into a string, then use a string stream to read the number, as shown in Example 9-2.

Example 9-2. Reading a number from a fixed-width field
template<typename T, typename charT, typename traits>

std::basic_istream<charT, traits>&

  fixedread(std::basic_istream<charT, traits>& in, T& x)

{

  if (in.width(  ) == 0)

    // Not fixed size, so read normally.

    in >> x;

  else {

    std::string field;

    in >> field;

    std::basic_istringstream<charT, traits> stream(field);

    if (! (stream >> x))

      in.setstate(std::ios_base::failbit);

  }

  return in;

}

The only other flags that affect input are basefield and boolalpha:

  • The basefield flag determines how integers are interpreted. If basefield is nonzero, it specifies a fixed radix (oct, hex, or dec), or if basefield is 0 (the default), the input determines the radix: leading 0x or 0X for hexadecimal, leading 0 for octal, decimal otherwise.

  • If the boolalpha flag is set, a formatted read of bool reads a string, which must match the names true or false (in the stream's locale, according to the numpunct facet). If the boolalpha flag is not set, a bool is read as a long integer, and the number is converted to bool using the standard rules: nonzero is true and 0 is false. By default, the flag is clear (false).

Floating-point numbers are accepted in fixed or scientific format.

The decimal point character is determined by the stream's locale, as is the thousands separator. Thousands separators are optional in the input stream, but if present, they must match the locale's thousands separator character and grouping rules. For example, assuming that the thousands separator is , and the grouping is for every 3 characters (grouping( ) returns "\3"), the following are three valid input examples and one invalid example:

1,234,567          // Valid

1,234,56           // Invalid

1234567            // Valid

1234,567           // Valid

When reading data that the user types, you should imbue the input stream with the user's native locale (e.g., cin.imbue(locale(""))). For input that is being read from files or other sources that require portable data formats, be sure to use the "C", or classic, locale (e.g., cin.imbue(locale::classic( ))).

See the num_get facet in the <locale> section of Chapter 13 for details on how numeric input is parsed and interpreted.

9.2.2 Formatted Output

The formatted output functions are the overloaded operator<< functions. They all work similarly, using the flags and other information to format a value as a string. The string is then padded with zero or more copies of a fill character to achieve the desired width. The adjustfield flags are used to determine where the fill characters are added (to the left, right, or internal, with internal meaning after a sign or a leading 0x or 0X).

The padded string is written to the output stream, and the stream's width is reset to 0. The width is the only formatting parameter that is reset. The flags, precision, and the fill character are "sticky" and persist until they are changed explicitly.

Formatting an integer depends on the basefield (hex, oct, or dec), uppercase (0X for hexadecimal), showpos (insert a + for positive numbers), and showbase (to insert a prefix of 0x or 0X for hexadecimal or 0 for octal) flags. The defaults are decimal, lowercase, no positive sign, and no base. If the locale's numpunct facet specifies thousands grouping, thousands separators are inserted at the specified positions.

Formatting a floating-point number depends on the floatfield (fixed, scientific, or 0 for general), uppercase (E for exponent), showpoint (insert decimal point even if not needed), and showpos (insert a + for positive numbers) flags. The defaults are general, lowercase, no point unless needed, and no positive sign.

If the boolalpha flag is set, bool values are written as names (e.g., true or false, or other strings, depending on the locale). If boolalpha is not set, bool values are written as integers (described earlier). The default flag is clear (false).

When writing output for a user's immediate consumption, you should imbue the output stream with the user's native locale (e.g., cout.imbue(locale(""))). For output that is being written to files or other sources that require portable data formats, be sure to use the "C", or classic, locale (e.g., cout.imbue(locale::classic( ))).

See the num_put facet in the <locale> section of Chapter 13 for details on how numeric output is formatted.