18

For performing file IO in C++ we use the ofstream, ifstream and fstream classes.

  • ofstream: Stream class to write on files
  • ifstream: Stream class to read from files
  • fstream: Stream class to both read and write from/to files

The process of associating a file with a stream object is called "opening the file". When opening a file we can specify the mode in which the file is to be opened. My query is related to the ios::out and ios:in modes.

When I create an ofstream object and open the file with ios::in mode, I am able to write into the file but only if its created already(with ios::out mode file is also created if it doesn't already exist).
But when I create ifstream object and open the file with ios::out mode, I am able to read from the file.

My question is why these modes (ios::in/ios::out) are supplied by the language when the type of the stream(ifstream/ofstream) itself specifies as to which type of operation(input/output) is being performed ?

Also why this ambiguous usage(ofstream with ios::in and ifstream with ios::out) works in one case and fails(though only if file is not already present) in another ?

SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
Arun
  • 3,138
  • 4
  • 30
  • 41

2 Answers2

14

The ofstream, ifstream and fstream classes are high level interfaces for the underlying filebuf, which one can access through the rdbuf() member function of the stream.

When you open an ofstream with some mode mode, it opens the underlying stream buffer with mode | ios_base::out. Analogously ifstream uses mode | ios_base::in. fstream passes the mode parameter verbatim to the underlying 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 previously stated, 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 opened it with ios_base::out:

g.rdbuf()->sputn("abc", 3); // we still have write access
Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
0

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.
SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105