For performing file IO in C++ we use the ofstream, ifstream and fstream classes.
Because the mode is not limited to input/output. The constructor of ifstream
, for example, looks like:
explicit ifstream ( const char * filename, ios_base::openmode mode = ios_base::in );
Note the default value is ios_base::in
, so you don't have to specify it yourself. However, the mode
sets the streams flags which are not limited to in
/out
, but include:
app
(append) Set the stream's position indicator to the end of the stream before each output operation.ate
(at end) Set the stream's position indicator to the end of the stream on opening.binary
(binary) Consider stream as binary rather than text.in
(input) Allow input operations on the stream.out
(output) Allow output operations on the stream.trunc
(truncate) Any current content is discarded, assuming a length of zero on opening.The ofstream
, ifstream
and fstream
classes are high level interfaces for the underling filebuf
, which one can get through the rdbuf()
member function of the stream.
According to the standard when you open an ofstream
with some mode mode
, it opens the underlining stream buffer as with mode | ios_base::out
. Analogously ifstream
uses mode | ios_base::in
. fstream
passes the mode
parameter verbatim to the underlining stream buffer.
What the above implies is that the following code opens the file with exactly the same open flags:
fstream f("a.txt", ios_base::in | ios_base::out);
ifstream g("a.txt", ios_base::out);
ofstream h("a.txt", ios_base::in);
After these lines you can do exactly the same things with f.rdbuf()
, g.rdbuf()
and h.rdbuf()
, and all the three act as if you opened the file with the C call fopen("a.txt", "r+")
, which gives you read/write access, does not truncate the file, and fails if the file does not exist.
So, why do we have three different classes? As I've already said, these are high level classes providing a high-level interface over the lower-level stream buffer. The idea is that ifstream
has member functions for input (like read()
), ofstream
has member functions for output (like write()
) while fstream
has both. For example you cannot do this:
g.write("abc", 3); // error: g does not have a write function
But this works, because, although g
is an ifstream
, we had opened it with ios_base::out
:
g.rdbuf()->sputn("abc", 3); // we still have write access