C++ Programming Language: Stream IO and File IO
C++ Programming Language: Stream IO and File IO
| HOME
C++ Programming
1.1 Streams
1.2 C++ IO Headers, Templates an
1.3 Buffered IO
Language 1.4 The <iostream> Header and t
1.5 The Stream Insertion << and S
1.6 The ostream Class
Stream IO and File IO 1.7 The istream class
1.8 Unformatted Input/Output Fu
1.9 States of stream
1.10 Formatting Input/Output via
The C language did not build the input/output facilities into the language. In other 1.11 The C++ string class Input/
words, there is no keyword like read or write. Instead, it left the IO to the
2. File Input/Output (Header <fstr
compiler as external library functions (such as printf and scanf in stdio library).
2.1 File Output
The ANSI C standard formalized these IO functions into Standard IO package
2.2 File Input
(stdio.h). C++ continues this approach and formalizes IO in libraries such as
2.3 Example on Simple File IO
iostream and fstream. 2.4 Binary file, read() and write
2.5 Random Access File
Features 3. String Streams
C++ IO is type safe. IO operations are defined for each of the type. If IO
operations are not defined for a particular type, compiler will generate an
error.
C++ IO operations are based on streams of bytes and are device independent. The same set of operations can be applied
to different types of IO devices.
1. Stream IO
1.1 Streams
C/C++ IO are based on streams, which are sequence of bytes flowing in and out of the programs (just like water and oil
flowing through a pipe). In input operations, data bytes flow from an input source (such as keyboard, file, network or another
program) into the program. In output operations, data bytes flow from the program to an output sink (such as console, file,
network or another program). Streams acts as an intermediaries between the programs and the actual IO devices, in such the
way that frees the programmers from handling the actual devices, so as to archive device independent IO operations.
C++ provides both the formatted and unformatted IO functions. In formatted or high-level IO, bytes are grouped and
converted to types such as int, double, string or user-defined types. In unformatted or low-level IO, bytes are treated as raw
bytes and unconverted. Formatted IO operations are supported via overloading the stream insertion (<<) and stream
extraction (>>) operators, which presents a consistent public IO interface.
Headers
C++ IO is provided in headers <iostream> (which included <ios>, <istream>, <ostream> and <streambuf>), <fstream>
(for file IO), and <sstream> (for string IO). Furthermore, the header <iomanip> provided manipulators such as setw(),
setprecision()setfill() and setbase() for formatting.
Template Classes
In order to support various character sets (char and wchar_t in C++98/03; and char16_t, char32_t introduced in C++11),
the stream classes are written as template classes, which could be instantiated with an actual character type. Most of the
template classes take two type parameters. For example,
where:
charT is the character type, such as char or wchar_t;
traits, of another template class char_traits<charT>, defined the properties of the character operations such as the
collating sequence (sorting order) of character set.
ios_base and ios: superclasses to maintain common stream properties such as format flag, field width, precision and
locale. The superclass ios_base (which is not a template class) maintains data that is independent of the template
parameters; whereas the subclass ios (instantiation of template basic_ios<char>) maintains data which is dependent
of the template parameters.
istream (basic_istream<char>), ostream (basic_ostream<char>): provide the input and output public interfaces.
iostream (basic_iostream<char>): subclass of both istream and ostream, which supports bidirectional input and
output operations. Take note that istream and ostream are unidirectional streams; whereas iostream is bidirectional.
basic_iostream template and iostream class is declared in the <istream> header, not <iostream> header.
ifstream, ofstream and fstream: for file input, output and bidirectional input/output.
istringstream, ostringstream and stringstream: for string buffer input, output and bidirectional input/output.
streambuf, filebuf and stringbuf: provide memory buffer for the stream, file-stream and string-stream, and the
public interface for accessing and managing the buffer.
1.3 Buffered IO
[TODO]
1.4 The <iostream> Header and the Standard Stream Objects: cin, cout, cerr
and clog
The <iostream> header also included the these headers: <ios>, <istream>, <ostream> and <streambuf>. Hence, your
program needs to include only the <iostream> header for IO operations.
Take note that cin/cout shall be the left operand and the data flow in the direction of the arrows.
The << and >> operators are overloaded to handle fundamental types (such as int and double), and classes (such as
string). You can also overload these operators for your own user-defined types.
The cin << and cout >> return a reference to cin and cout, and thus, support cascading operations. For example,
The << operator returns a reference to the invoking ostream object. Hence, you can concatenate << operations, e.g., cout
<< 123 << 1.13 << endl;.
The << operator is also overloaded for the following pointer types:
const char *, const signed char *, const unsigned char *: for outputting C-strings and literals. It uses the
terminating null character to decide the end of the char array.
void *: can be used to print an address.
For example,
// Manipulator - std::flush
ostream & flush (ostream & os);
// Example
cout << "hello" << flush;
2. endl manipulator, which inserts a newline and flush the buffer. Outputting a newline character '\n' may not flush the
output buffer; but endl does.
// Manipulator - std::endl
ostream & endl (ostream & os)
The >> operator returns a reference to the invokind istream object. Hence, you can concatenate >> operations, e.g., cin >>
number1 << number2 <<....
The >> operator is also overloaded for the following pointer types:
const char *, const signed char *, const unsigned char *: for inputting C-strings. It uses whitespace as
delimiter and adds a terminating null character to the C-string.
// Examples
cin.ignore(numeric_limits<streamsize>::max()); // Ignore to the end-of-file
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // Ignore to the end-of-line
// ostream class
ostream & put (char c); // put char c to ostream
// Examples
cout.put('A');
cout.put('A').put('p').put('p').put('\n');
cout.put(65);
// istream class
// Single character input
int get ();
// Get a char and return as int. It returns EOF at end-of-file
istream & get (char & c);
// Get a char, store in c and return the invoking istream reference
// C-string input
istream & get (char * cstr, streamsize n, char delim = '\n');
// Get n-1 chars or until delimiter and store in C-string array cstr.
// Append null char to terminate C-string
// Keep the delim char in the input stream.
istream & getline (char * cstr, streamsize n, char delim = '\n');
// Same as get(), but extract and discard delim char from the
// input stream.
// Examples
int inChar;
while ((inChar = cin.get()) != EOF) { // Read till End-of-file
cout.put(inchar);
}
[TODO] Example
// ostream class
ostream & write (const char * buf, streamsize n)
// Write n character from char array.
// Example
[TODO]
1.9 States of stream
The steam superclass ios_base maintains a data member to describe the states of the stream, which is a bitmask of the type
iostate. The flags are:
eofbit: set when an input operation reaches end-of-file.
failbit: The last input operation failed to read the expected characters or output operation failed to write the expected
characters, e.g., getline() reads n characters without reaching delimiter character.
badbit: serious error due to failure of an IO operation (e.g. file read/write error) or stream buffer.
These flags are defined as public static members in ios_base. They can be accessed directly via ios_base::failbit or via
subclasses such as cin::failbit, ios::failbit. However, it is more convenience to use these public member functions of
ios class:
By default, the values are displayed with a field-width just enough to hold the text, without additional leading or trailing
spaces. You need to provide spaces between the values, if desired.
For integers, all digits will be displayed, by default. For example,
For floating-point numbers, the default precison is 6 digits, except that the trailing zeros will not be shown. This default
precision (of 6 digits) include all digits before and after the decimal point, but exclude the leading zeros. Scientific
notation (E-notation) will be used if the exponent is 6 or more or -5 or less. In scientific notation, the default precision is
also 6 digits; the exponent is displayed in 3 digits with plus/minus sign (e.g., +006, -005). For example,
cout << "|" << 1.20000 << "|" << endl; // |1.2| (trailing zeros not displayed)
cout << "|" << 1.23456 << "|" << endl; // |1.23456| (default prec
precision is 6 digits)
cout << "|" << -1.23456 << "|" << endl; // |-1.23456|
cout << "|" << 1.234567 << "|" << endl; // |1.23457|
cout << "|" << 123456.7 << "|" << endl; // |123457|
cout << "|" << 1234567.89 << "|" << endl; // |1.23457e+006| (scientific-notation for e>=6)
cout << "|" << 0.0001234567 << "|" << endl; // |0.000123457| (leading zeros not counted towards prec
precision)
cout << "|" << 0.00001234567 << "|" << endl; // |1.23457e-005| (scientific-notation for e<=-5)
However, it is more convenience to use the so-called IO manipulators, which returns a reference to the invoking stream
object and thus can be concatenated in << operator (e.g., cout << setfill(':') << left << setw(5) <<...). They are:
The default field-width is 0, i.e., just enough space to display the value. C++ never truncates data, and will expand the field to
display the entire value if the field-width is too small. The setw() operation is non-sticky. That is, it is applicable only to the
next IO operation, and reset back to 0 after the operation. The field-width property is applicable to both output and input
operations.
Except setw(), all the other IO manipulators are sticky, i.e., they take effect until a new value is set.
Example: Alignment
The internal alignment left-align the sign, but right-align the number, as illustrated.
You can also use ostream's member function width() (e.g. cout.width(n)) to set the field width, but width() cannot be
used with cout << operator.
Again, it is more convenience to use IO manipulators, which can be concatenated in <<. They are:
setprecision() manipulator (in <iomanip> header) to set the precision of floating-point number.
fixed|scientific manipulators (in <iostream> header) to set the floating-point display format.
Floating point number can be display in 3 formatting modes: default|fixed|scientific. The precision is interpreted
differently in default and non-default modes (due to legacy).
In default mode (neither fixed nor scientific used), a floating-point number is displayed in fixed-point notation (e.g.,
12.34) for exponent in the range of [-4, 5]; and scientific notation (e.g., 1.2e+006) otherwise. The precision in default
mode includes digits before and after the decimal point but exclude the leading zeros. Fewer digits might be shown as
the trailing zeros are not displayed. The default precision is 6. See the earlier examples for default mode with default
precision of 6.
As mentioned, the trailing zeros are not displayed in default mode, you can use manipulator showpoint|noshowpoint
to show or hide the trailing zeros.
In both fixed (e.g., 12.34) and scientific (e.g., 1.2e+006), the precision sets the number of digits after decimal point.
The default precision is also 6.
For examples,
// fixed-point formatting
cout << fixed;
cout << "|" << 1234567.89 << "|" << endl; // |1234567.890000|
// default prec
precision is 6, i.e., 6 digits after the decimal point
// scientific formatting
cout << scientific;
cout << "|" << 1234567.89 << "|" << endl; // |1.234568e+006|
// default prec
precision is 6, i.e., 6 digits after the decimal point
// Test precision
prec
cout << fixed << setprecision(2)
prec ; // sticky
cout << "|" << 123.456789 << "|" << endl; // |123.46|
cout << "|" << 123. << "|" << endl; // |123.00|
You can also use ostream's member function precision(n) (e.g. cout.precision(n)) to set the floating-point precision,
but precision() cannot be used with cout << operator.
hex|dec|oct: Set the integral number base. Negative hex and oct are displayed in 2's complement format.
Alternatively, you can use setbase(8|10|16) (in header <iomanip>).
showbase|noshowbase: write hex values with 0x prefix; and oct values with 0 prefix.
showpos|noshowpos: write positive dec value with + sign.
uppercase|nouppercase: write uppercase in certain insertion operations, e.g., hex digits. It does not convert characters
or strings to uppercase!
For examples,
Other manipulators
skipws|noskipws: skip leading white spaces for certain input operations.
unitbuf|nounibuf: flush output after each insertion operation.
Notes
You need to include the <iomanip> header for setw(), setprecision(), setfill(), and setbase().
You can use ios_base's (in <iostream> header) member functions setf() and unsetf() to set the individual
formatting flags. However, they are not as user-friendly as using manipulators as discussed above. Furthermore, they
cannot be used with cout << operator.
File IO requires an additional step to connect the file to the stream (i.e., file open) and disconnect from the stream (i.e., file
close).
2.1 File Output
The steps are:
1. Construct an ostream object.
2. Connect it to a file (i.e., file open) and set the mode of file operation (e.g, truncate, append).
3. Perform output operation via insertion >> operator or write(), put() functions.
4. Disconnect (close the file which flushes the output buffer) and free the ostream object.
#include <fstream>
.......
ofstream fout;
fout.open(filename, mode);
......
fout.close();
By default, opening an output file creates a new file if the filename does not exist; or truncates it (clear its content) and starts
writing as an empty file.
void close (); // Closes the file, flush the buffer and disconnect from stream object
File Modes
File modes are defined as static public member in ios_base superclass. They can be referenced from ios_base or its
subclasses - we typically use subclass ios. The available file mode flags are:
1. ios::in - open file for input operation
2. ios::out - open file for output operation
3. ios::app - output appends at the end of the file.
You can set multiple flags via bit-or (|) operator, e.g., ios::out | ios::app to append output at the end of the file.
For output, the default is ios::out | ios::trunc. For input, the default is ios::in.
2.2 File Input
The steps are:
1. Construct an istream object.
2. Connect it to a file (i.e., file open) and set the mode of file operation.
3. Perform output operation via extraction << operator or read(), get(), getline() functions.
4. Disconnect (close the file) and free the istream object.
#include <fstream>
.......
ifstream fin;
fin.open(filename, mode);
......
fin.close();
Program Notes:
Most of the <fstream> functions (such as constructors, open()) supports filename in C-string only. You may need to
extract the C-string from string object via the c_str() member function.
You can position the input pointer via seekg() and output pointer via seekp(). Each of them has two versions: absolute and
relative positioning.
Random access file is typically process as binary file, in both input and output modes.
[TODO] Example
3. String Streams
C++ provides a <sstream> header, which uses the same public interface to support IO between a program and string
object (buffer).
The string streams is based on ostringstream (subclass of ostream), istringstream (subclass of istream) and bi-
directional stringstream (subclass of iostream).
ostringstream
explicit ostringstream (ios::openmode mode = ios::out); // default with empty string
explicit ostringstream (const string & buf,
ios::openmode mode = ios::out); // with initial str
For example,
// Get contents
cout << sout.str() << endl;
istringstream
explicit istringstream (ios::openmode mode = ios::in); // default with empty string
explicit istringstream (const string & buf,
ios::openmode mode = ios::in); // with initial string
For example,
Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan ([email protected]) | HOME