[Concepts]
[Classes]
[Predefined streams]
[Input]
[Output]
[References]
[Background Information]
C++ Input/Output
Users want a high degree of control over
formatting, but also want high performance and ease of use.
Before we see how C++ attempts to reconsile these needs, let's consider
I/O in more detail in an attempt to justify C++'s solution.
- streams -
I/O uses the concept of streams - a flow of characters. These
characters may be 1 byte or 2 byte ('wide'), the latter necessary for
languages with many characters. streams may flow into or out of files.
They can also flow into and out of strings. C++ tries to offer the
same set of commands whatever the nature of the source and destination.
- buffers -
It would be inefficient to update a file on disc each time a character
was added. The character is written into a buffer, and when
enough characters are in the buffer to make updating worthwhile, the
buffer is flushed and the file on disc updated. C++ offers ways
to control the behaviour of buffers, but often the default is ok.
- state - Each stream has state information indicating whether
an error has occured, etc.
- locale -
The natural language required by the user has an influence on output -
should a bool value be printed out as true or
vero? Such preferences are controlled by the locale,
which is usually set up appropriately by default.
True to form, C++ represents each distinct concept with a class, and
tries to 'factor out' components that are needed in more than one class.
Usually users don't have to worry too much about this (skip to
the Input section now if you want), but some
awareness of this structure will help you understand the online
documentation and help you decide which include files to use.
The class hierarchy (inheritance tree) is as follows
ios_base
ios
/\
/ \
/ \
istream ostream
/ | \ / | \
/ | | | \
/ / | \ \
/ / | \ \
/ / | \ \
istring ifstream iostream ofstream ostring
stream /\ stream
/ \
fstream stringstream
so if the user used a ifstream to get input from a file,
the istream (input) features, state information (in
ios_base) and format/buffer control (via ios)
would be available.
The following streams are predefined:
- cin - the standard source of input (often the keyboard)
- cout - the standard destination for output (often the terminal window)
- cerr - the standard destination for error messages (often the terminal window). Output through this
stream is unit-buffered, which means that characters are
flushed after each block of characters is sent.
- clog - like cerr, but its output is buffered.
Initialisation
To input data you first need to create a stream and associate
it with a file or string so that the stream knows where to get
the characters from. Unless you're using cin (the standard
input stream - usually the keyboard) you'll need to
use the open command, or a constructor. You can provide extra arguments,
but usually you just need to provide a filename.
As a simple example consider the following, which reads then displays 3 numbers
from a file.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
int i;
ifstream fin;
fin.open("test"); // test contains 3 ints
for (int j=0;j<3;j++)
{
fin >> i;
cout << i << endl;
}
fin.close();
}
This program lacks error-checking -
if the file doesn't exist, or if it contains less than 3 integers then the
program won't work well. Even if the file's ok, it's rather dangerous to
ever read from it before checking first. For instance, in the program
above if you put the
fin.close(); line inside the loop (at the end), the stream will be closed
after
the first number is read, but the program will still happily print erroneous
values out for the last two numbers and won't complain.
You can check
for success by calling the stream's good() function.
To read a line of text (including spaces) into a string, use getline()
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
string s;
ifstream fin;
fin.open("/etc/passwd");
while(getline(fin,s))
cout << s << endl;
}
The file will be opened at its start. If you don't want to access the
contents sequentially, you can use seekg() to set the
file-position indicator, and tellg() to tell you the current
position. The following program prints the first and last characters
of the file given to it as an argument. Note the use of ios::beg
(beg is defined in ios) to show that you're offsetting
from the beginning of the file.
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
string fileName;
bool flag=false;
if (argc==2)
fileName=argv[1];
else {
cerr << "Provide a single filename next time" << endl;
return 1;
}
ifstream fin;
fin.open(fileName.c_str());
while(fin.good() == false)
{
cout << "Unable to open file. Enter a new name: ";
cin >> fileName;
fin.open(fileName.c_str());
}
istream ist=(fin.rdbuf());
ist.seekg(0,ios::beg);
streampos pos=ist.tellg();
cout << "Initial Position=" << pos << endl;
char c;
ist.get(c);
cout << "Char=" << c<< endl;
ist.seekg(-1,ios::end);
pos=ist.tellg();
cout << "Final Position=" << pos << endl;
ist.get(c);
cout << "Char=" << c <<endl;
return 0;
}
Routines
As well as being able to use ">>" as usual on an open file
there are also various forms of the get command (to read raw data)
as well as getline to read a line of text with spaces.
Other member functions include
- ignore(n,d) - throws away up to n characters. Stops if it
reaches the character specified by 'd'.
- gcount() - returns the number of characters extracted by the last
unformatted input function.
- peek() - returns the next character without extracting it
- putback(c) - attempts to put back the just-read character 'c'
And remember to call the close() member function when you've
finished with a file.
Further information for local users is on the basic_istream page.
Manipulators
When, during output, you use "<< endl" you are using a
manipulator. There are a few input manipulators too
- cin >> noskipws; (or cin >> ws; in older versions) - don't skip white space
- cin >> hex; - base 16
- cin >> dec; - base 10
- cin >> oct; - base 8
Initialisation
To output data you first need to create a stream and associate
it with a file or string so that the stream knows where to deliver
the characters. You can use a constructor or the open
member function to open a file for writing.
Routines
Once the stream is in operation you can use "<<" as usual.
So
...
ofstream fout;
fout.open("MyFilename");
fout << "test";
should work.
Other member functions include
- write(const char* ptr, int n); (for raw data)
- seekp(off,dir) (repositions the 'put' pointer)
- tellp() (returns the 'put' pointer value)
Formatting
This requires C++ knowing how to convert values of various types
into characters. C++ can deal with the standard types automatically,
but even with these the user may wish to format the output.
Formatting is controlled by flags in ios_base. These can be
set using the member functions below or by using manipulators
- fill(c) - pad fields with the 'c' character (usually the space character)
- width(i) - sets the field width to i
- adjustfield - a flag to set alignment in fields: left,
right or
internal
- precision(i) - sets the number of significant digits displayed
in floating point numbers
- floatfield - a flag to set the style for floating point numbers:
scientific (exponential notation) or
fixed.
The setf function can be called to set flags, and the following
manipulators are available
- cout << endl; - newline
- cout << ends; - newline (when writing to a string)
- cout << flush; - flush buffer
- cout << hex; - base 16
- cout << dec; - base 10
- cout << oct; - base 8
- cout << setprecision(5); - set floating point format
Here's a short example
#include <iostream>
#include <iomanip> // to use the setprecision manipulator
using namespace std;
int main()
{
cout << 1331 <<endl;
cout << "In hex " << hex<< 1331 <<endl;
cout << 1331.123456 <<endl;
cout.setf(ios::scientific,ios::floatfield);
cout <<1331.123456 <<endl;
cout << setprecision(3) << 1331.123456 <<endl;
cout << dec << 1331 <<endl;
cout.fill('X');
cout.width(8);
cout << 1331 <<endl;
cout.setf(ios::left,ios::adjustfield);
cout.width(8);
cout << 1331 <<endl;
return 0;
}
Local users can read more details on the ios_base and basic_ios pages.
Strings
Once you can do I/O to and from files, I/O to and from strings is very similar, except that you
don't need an "open()" call. The following example writes (i.e. converts) an integer into a string.
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
int main()
{
stringstream s;
string t;
int x = 10;
s << x;
s >> t;
cout << "t=" << t << endl;
return 0;
}
Booleans
You can print out bools as numerical values or as words.
The following should print out "1" then "true"
(translated into your chosen language).
cout << true << endl;
cout << boolalpha;
cout << true;
CUED users can read the pages for
The
code above works with HP-UX's aCC compiler (version A.03.31).
Note that cerr << "x"; runs cerr.operator<<("x");. By further redefining the "<<" operator you can control the output
format of user-defined types.
[1A C++ Frequently Asked Questions]
[C++ FAQ LITE Frequently Asked Questions]
[C++]
[Help]
Updated in June 2002
tpl@eng.cam.ac.uk