This page contains a summary of many things you may find it useful to know when dealing with input and output in C++, whether it be standard I/O, or file I/O. The starting point for much of the material that you will find here was Chapter 8 of Neill Graham's Learning C++ (McGraw-Hill, 1991). That chapter, though somewhat outdated at the time of this writing (summer, 2003), still contains an excellent short summary of C++ I/O. A number of other references from the Annotated C++ Book List were also consulted in the preparation of this page. This material is very difficult to find all in one place and in useful summary form. Since the current presentation is unlikely to be regarded as definitive, comments are welcome.

Contents of this Web Page
Topics
Tables

The current page will be most useful to you if all of the following are true, and this is what the page assumes:

The purpose of the current page is to provide more detailed information on some of the more commonly used I/O facilities that are available from the C++ Stream-Related Headers. For convenience, some of that information is repeated on this web page, and there are also direct links from this page to various parts of that material.

The Basic Input/Output Classes and Facilities

The Four Basic Input/Output Classes

The four basic input/output classes are pictured below in a simple UML class diagram, which shows their (multiple-inheritance) relationship. (By the way, UML = Unified Modeling Language, a language for describing, among other things, C++ class relationships by the use of diagrams like that shown.) Class ios is the (virtual) base class for both istream and ostream, which are both, in turn, base classes for iostream.

All of these classes are generally available by including the <iostream> header. However, it is worth pointing out that the Standard does not require that the iostream header automatically include the ios, istream and iostream headers, and in any case it is just good programming practice to include explicitly each header you need, even if it might be included by another header you are using.

Basic Facilities Provided by the Basic Classes

Class ios provides a number of basic facilities used by all the other input/output classes, and which include the features in the list shown below. See this part of the Standard Library Reference on this site for additional details.

Class istream provides facilities for reading formatted input, including an overloaded extraction operator, operator>>, and other input functions. See this part of the Standard Library Reference on this site for additional details.

Class ostream provides facilities for writing formatted output, including an overloaded insertion operator, operator<<, and other output functions. See this part of the Standard Library Reference on this site for additional details.

Class iostream provides facilities for both the reading and the writing of formatted output, which are inherited from istream and ostream. It also provides four "standard" objects for dealing with "standard I/O", as discussed in the following section. See this part of the Standard Library Reference on this site for additional details.

Standard Input/Output

Although a C++ program may read input from a variety of sources, and write output to a variety of destinations, the console keyboard and the console screen have traditionally been the source and destination (respectively) of program I/O. For that reason we generally refer to, and think of, the keyboard as the "standard input" for a C++ program, and the screen as the "standard output". Either or both of these may be "redirected" at run time to come from some other source, or go to some other destination, such as a file. How this is done, and whether it can be done at all, will depend on the operating system under which the program is running.

In addition to "standard output", C++ programs automatically provide a "standard error" object where error messages can be written, and a "standard log" where the program may write a log of whatever program activities may later be of interest. In the simplest case all of these "output" objects are tied to the console screen, but this is only the most frequent and obvious default. Here, then, are the four "Standard I/O" objects, made available by including the <iostream> header:

extern istream cin
The "standard input stream"
extern ostream cout
The "standard output stream"
extern ostream cerr
The "standard error stream"
extern ostream clog
The "standard log stream"

Each of these objects is initialized and "set up for business" before the main program begins, and none is destroyed during normal program execution, so they can all be used throughout the life of a program.

Format State: Flags and Parameters

A format state governs how output values will be printed and how input values will be interpreted, and consists of

Format-State Flags

Each format flag is designated by name with an ios constant, as shown in the table which follows. The table also gives the purpose of each flag. Note as well that there are certain groups of flags, called bit fields, three of which also have names provided by ios constants. Further details on these bit fields are given in the notes following the table. Some of these flags apply only to input streams, others only to output streams, while some apply to both. For more specific information on this, see the table of manipulators later on this page.

Format-State Flags
Flag Bit Field Flag Purpose
ios::left ios::adjustfield Left-justify all output
ios::right Right-justify all output
ios::internal Left-justify sign or base indicator, and right-justify rest of number
ios::dec ios::basefield Display integers in base 10 (decimal) format
ios::oct Display integers in base 8 (octal) format
ios::hex Display integers in base 16 (hexadecimal) format
ios::fixed ios::floatfield Use fixed point notation when displaying floating-point numbers (the usual convention)
ios::scientific Use exponential (i.e., scientific) notation when displaying floating-point numbers
ios::showbase   Show base indicator when displaying integer output
ios::showpoint Show decimal point when displaying floating-point numbers (default is 6 significant digits)
ios::showpos Show a leading plus sign (+) when displaying positive numbers
ios::uppercase Use uppercase E when displaying exponential or hexadecimal numbers
ios::boolalpha   Use textual rather than numerical format to read and write boolean values (true and false, rather than 1 and 0)
ios::skipws   Skip whitespace on input
ios::unitbuf   Flush output buffer after each insertion (which really has nothing to do with formatting)

Some notes to keep in mind about the contents of the above table:

  1. The default flag settings, which apply when no flag setting has been explicitly changed by a program, are
  2. In each of the three bit fields that have names provided by ios constants—namely, ios::adjustfield, ios::basefield and ios::floatfield—the corresponding flags are mutually exclusive. That is, only one of the flags in each of those bit fields can be set at any given time. This should be clear just by looking at the purpose of the flags in each bit field, as described in the above table.
  3. In the case of the three named bit fields, a formatting action is also specified in the case where no flag in the field is set, as follows:
  4. In the anonymous bit field that contains multiple flags, the flags are not mutually exclusive. And once again, this should be clear just by looking at the purpose of the flags in each bit field, as described in the above table.
  5. The bitwise OR operator can be used to combine flags (provided they are compatible. i.e., non-mutually exclusive), as in this situation using the setf function
    file.setf(ios::dec | ios::showpoint | ios::fixed)
    
    which would set all three indicated flags (and leave the other flags unchanged). The logical OR operator can also be used.

Format-State Parameters

A format state also has the following three parameters:

Persistence

As we have noted above, the fieldwidth parameter is not persistent, in that it only applies to the next input or output item. That begs the question: What about the fill character and the precision value–are they persistent? You should write a short sample program to perform some tests suitable for answering this question.

Setting, Saving and Re-Setting Format-State Flags and Parameters

Both format-state flags and format-state parameters can be controlled either by member functions of the stream classes, or by stream manipulators. This gives the programmer many options, and with this come the eternal compromises that have to be made between extra flexibility with extra power, and extra complexity with potential confusion.

Using Member Functions of Stream Classes

The following three stream member functions (note that the first two have two versions each) may be used to deal with format-state flags.

stream.flags()
Return a value of type fmtflags that contains the current values of all format-state flags
stream.flags(fmtflags_value)
Return a value of type fmtflags that contains the current values of all format-state flags, set all flags in fmtflags_value, and clear all flags not mentioned in fmtflags_value
stream.setf(fmtflags_value)
Set format-state flags specified in fmtflags_value, leave all other format-state flags unchanged, and return a value of type fmtflags that contains the previous state of all flags
stream.setf(fmtflags_value, fmtflags_group)
Set format-state flags specified in fmtflags_value as the new flags for the flag group identified by fmtflags_group, leave all other format-state flags unchanged, and return a value of type fmtflags that contains the previous state of all flags

Typical uses of the two-parameter version of this function look like this:

stream.setf(ios::left, ios::adjustfield)
stream.setf(0, ios::floatfield)
That second example above clears all flags in the ios::floatfield bit field.
stream.unsetf(fmtflags_value)
Clear format-state flags specified in fmtflags_value and leave all other format-state flags unchanged

The following three stream member functions (each with two versions) may be used to deal with format-state parameters.

stream.fill()
Return current fill character format-state parameter value as a value of type char
stream.fill(char_value)
Return current fill character format-state parameter value as a value of type char, and set fill character format-state parameter to new value in char_value
stream.precision()
Return current precision format-state parameter value as a value of type streamsize
stream.precision(streamsize_value)
Return current precision format-state parameter value as a value of type streamsize, and set precision format-state parameter to new value in streamsize_value
stream.width()
Return current fieldwidth format-state parameter value as a value of type streamsize
stream.width(streamsize_value)
Return current fieldwidth format-state parameter value as a value of type streamsize, and set fieldwidth format-state parameter to new value in streamsize_value
Using Manipulators

A manipulator is a function object that can be used as an operand to an input or output operator to manipulate a stream. There are two kinds of manipulators, those that take parameters and those that do not. Many manipulators have names that suggest the format-state flags that they set, or unset, or the format-state parameters they give values to, for that is what many (but not all) manipulators do.

The following tables show the available manipulators, and indicate, where applicable, the relationships between format-state flags and manipulators, or between format-state parameters and manipulators. The last column in each table indicates whether a given manipulator (and any associated flag or parameter) applies to input streams only, to output streams only, or to both input and output streams.

Member Functions vs. Manipulators: When do we use which?

Because we have two distinct ways of setting both format-state flags and format-state parameters, the obvious question of when to use which method arises. The key thing to keep in mind when answering this question is this: The member functions all return the current state of whatever you happen to be setting, if you are using the version of one of these functions that takes one or more parameters. The manipulators, on the other hand, do not return the current state. So, if you wish to retain the current state for any reason (to reset the stream to that original state later, for example), then use one or more member functions to set the state; otherwise, it doesn't matter.

Manipulators without Parameters
Manipulators Corresponding
Format-State Flags
Manipulator Purpose Input/Output
left ios::left Turn the flag on output
right ios::right Turn the flag on output
internal ios::internal Turn the flag on output
dec ios::dec Turns flag on output
oct ios::oct Turn the flag on input/output
hex ios::hex Turn the flag on input/output
fixed ios::fixed Turns the flag on output
scientific ios::scientific Turn the flag on output
showbase
noshowbase
ios::showbase Turn the flag on/off output
showpoint
noshowpoint
ios::showpoint Turn the flag on/off output
showpos
noshowpos
ios::showpos Turn the flag on/off output
uppercase
nouppercase
ios::uppercase Turn the flag on/off output
boolalpha
noboolalpha
ios::boolalpha Turns flag on/off input/output
skipws
noskipws
ios::skipws Turn the flag on/off input
unitbuf
nounitbuf
ios::unitbuf Turn the flag on/off output
endl N/A Output a newline character
and flush the stream
output
ends N/A Output a null output
flush N/A Flush the stream output
ws N/A Skip leading whitespace input

See this part of the Standard Library Reference on this site for additional details on manipulators without parameters.

Manipulators with Parameters
Manipulator Corresponding
Format-State
Flag(s)
Manipulator Purpose Input/Output
setbase(int_radix_value) ios::dec,
ios::oct, or
ios::hex
Set the number base to int_radix_value (10, 8 or 16) input/output
setiosflags(fmtflags_value)
resetiosflags(fmtflags_value)
As specified by fmtflags_value Turn the flags specified in fmtflags_value on/off input/output
Manipulator Corresponding
Format-State
Parameter
Manipulator Purpose Input/Output
setfill(int_char_code) fill character Set the fill character to the character whose code is specified by int_char_code output
setprecision(int_num_digits) precision Set the number of digits of precision to int_num_digits output
setw(int_width) width Set the fieldwidth in the output to int_width, which must be >= 0; for input of strings, the maximum number of characters read in will be one less than int_width (ensures that the input will fit into a char array whose size is given by int_width) input/output

See this part of the Standard Library Reference on this site for additional details on manipulators with parameters.

Input/Output for Streams Associated with Named Files (Text and Binary)

Although the "Standard I/O objects" (cin, cout, cerr and clog) are very convenient for some purposes, such as for I/O in testing and pedagogical situations and reporting errors to the console, in the real world C++ programs spend much more time dealing with data that comes from other sources, and is sent to other destinations, such as files on disk.

Textfiles Compared and Contrasted with Binary Files

Files fall into two major categories—textfiles and binary files—whose differences are summarized in the following table.

Comparison of Textfiles and Binary Files
Textfiles Binary Files
Easy for humans to read Impossible for humans to read
Easy to modify Harder to modify
Easy to transfer Harder to transfer
Slower access Faster access
Less accurate (subject to
conversion and roundoff errors)
Data stored exactly
Less compact storage More compact storage

 

Classes for File Streams

An expanded form of the UML class diagram given previously is show below, and illustrates the additional classes that are needed to deal with files. Those classes above the horizontal line are generally available by including <iostream>, and those below the line by including <fstream>, but be reminded once again that it's a good idea to include explicitly the header containing any class (or other entity) that you wish to use.

 

 

Input/Output Modes for File Streams

Before a program can gain access to a physical file for input or output, a "stream object" must be created and connected to the designated physical file. This can be done in essentially two ways: by the constructor when the stream object (stream variable, if you like) is declared, or later by calling an "open" member function with the stream object as target.

Also, files may be "opened" in various "modes", which are summarized in the following table.

File Stream Modes (Values of Type openmode)
openmode Literal Description
ios::in Open in input (read) mode
ios::out Open in output (write) mode
ios::app Open in append mode
ios::ate Go to end of file when opened
ios::binary Open in binary mode (default is text mode)
ios::trunc If file exists, delete file contents

You may also occasionally encounter the non-standard modes ios::nocreate (if file does not exist, open for output will fail) and/or ios::noreplace (if file exists, open for output will fail), but these should not be used in new code that attempts to be standard-compliant.

Some notes to keep in mind about the contents of the above table:

  1. By default a file is opened in "text mode", which does not have a corresponding explicit openmode literal constant. To open a file in binary mode, you must use ios::binary explicitly.
  2. A file stream object of type istream is opened by default in input mode (ios::in).
  3. A file stream object of type ostream is opened by default in output mode (ios::out), which will discard the contents of a pre-existing file of the same name as the one being opened. If you wish to avoid overwriting an output file and instead append to its end, it must be opened in append mode (ios::app).
  4. Just like format-state flags, these modes for opening a file may be combined by the bitwise OR or logical OR operators, as illustrated in the next item in this list.
  5. A file stream object of type fstream is opened by default in input/output mode (ios::in | ios::out), i.e., capable of being both read from and written to.

Detecting Errors and End-Of-File

When a program attempts to read input data from a stream, many things can go wrong. For example, the physical source that the program is looking for may not even exist, or may be inaccessible for some reason. Or, during the course of reading the input, values that are malformed in some way may be encountered, there may be fewer values than expected, and so on. It is therefore necessary to have some means of dealing with the various errors that may arise.

Also, streams may be in various "states", which are summarized in the following table.

Stream States (Values of Type iostate)
iostate Literal Description
ios::goodbit No problems with the stream
ios::badbit Irrecoverable error
ios::failbit Failure to read or write expected characters
ios::eofbit End-of-file encountered when reading

In C++ a stream variable is often examined as a boolean quantity. If is is "true" (non-zero) the stream may be assumed to be in a "good" state (nothing untoward has happened), while if it is "false" (zero or null), something "not so good" has happened and appropriate action should be taken. This simple approach is often used when attempting to open a file, usually for input, to test for existence, and when reading input.

For more detailed handling of errors, class ios provides the four functions shown below for testing the error state of a stream. Each of these functions returns true (non-zero) if the corresponding error condition holds, and false (zero) otherwise.

stream.good()
Return true if no error has occurred (i.e., the next three functions all return false)
stream.eof()
Return true if end-of-file has been encountered while attempting an input operation
stream.fail()
Return true if an input or output operation failed
stream.bad()
Return true if input or output error was so severe that recovery is unlikely

Some notes on these functions:

  1. When good() returns false, no further operations on the stream can be performed, at least until clear() has been called to reset flags and prepare the way for a retry. If bad() is true, this may not be possible, but if bad() is false but fail() is true (for example) it may be worth calling clear() and trying again.
  2. When an input operation is attempted after all input data has been read, the operation fails and both eof() and fail() will return true, eof() because an end-of-file has been encountered, and fail() because an input operation failed. This state of affairs may not represent a real error, but simply a condition indicating that all input has been read.

Direct Access (or "Random Access") to File Data

By default, files are read from, and written to, sequentially. It is possible, however, to move directly to any valid "file position" within a file and start reading (or writing, as the case may be, depending on the mode used to open the file) at that point in the file. Although it is possible to read and write at "random" locations in textfiles, binary files are more likely candidates for this kind of program activity.

One or more of the three types shown next will be required for working with the functions shown below. Details on the functions themselves are available by following the associated links.

streamoff
An implementation-defined type that represents a signed offset in a stream [Values of type streamoff may be converted to values of type streamsize without losing information.]
streamsize
An implementation-defined signed integral type used to represent the size of various stream entities, such as the number of characters to read or write in an I/O operation [Values of type streamsize may be converted to values of type streamoff without losing information.]
Seek Origin for Seek Direction (Values of Type seekdir)
seekdir Literal Description
ios::beg Relative to beginning of stream (positive offset is absolute position)
ios::cur Relative to current stream position (negative offset toward beginning of stream, positive offset toward end of stream)
ios::end Relative to end of stream (negative offset toward begining of stream)

The following functions are the ones you would use for direct reading from a file (random file access for reading):

inStream.read(c_string_variable, streamsize_value)
Read up to streamsize_value characters, place them in c_string_variable, and return *this. [Note that no null character is appended to c_string_variable.]
inStream.gcount()
Return the number of characters returned from the stream by the most recent call to an unformatted member function (get(), getline(), ignore(), peek(), putback(), read() or unget()).
inStream.tellg()
Return current position in an input stream as a value of type streamoff. [The name tellg is short for "tell get", i.e., "tell" the position at which you may "get" a value.]
inStream.seekg(streamoff_value)
Move the "read pointer" in an input stream to the explicit position, or "offset" (measured by default from the beginning of the stream) specified by streamoff_value. [The name seekg is short for "seek get", i.e., "seek a (new) position at which you may "get" a value.]
inStream.seekg(streamoff_value, seekdir_value)
Move the "read pointer" in an input stream in a direction determined by seekdir_value and a distance specified by streamoff_value.

The following functions are the ones you would use for direct writing to a file (random file access for writing):

outStream.write(c_string_value, streamsize_value)
Write streamsize_value characters from c_string_value to the output stream and return *this.
outStream.tellp()
Return current position in an output stream as a value of type streamoff. [The name tellp is short for "tell put", i.e., "tell the position at which you may "put", or write, a value.]
outStream.seekp(streamoff_value)
Move the "write pointer" in an output stream to the explicit position, or "offset" (measured by default from the beginning of the stream) specified by streamoff_value. [The name seekp is short for "seek put", i.e., "seek" a (new) position at which you may "put", or write, a value.]
outStream.seekp(streamoff_value, seekdir_value)
Move the "write pointer" in an output stream in a direction determined by seekdir_value and a distance specified by streamoff_value.

Important Note

Though the fstream class is capable of both reading and writing a file alternately after the file has been opened simultaneously in both modes, care must be taken. In particular, note that it is not possible to switch between reading and writing arbitrarily. Once a read or write has taken place, the only way to switch between the two is to perform a seek operation. And if you don't actually want to move the file pointer, you can always seek to the current position, like this:

f.seekg(f.tellg(), ios::beg); //Seek to current file position

Failure to do this can result in unexplained or even bizarre behavior during subsequent actions on the file.