Opening Files with C++'s Iostreams

by Roger Pate (Kniht on EFnet)

Some Background Information

I would like to start off with a little bit of background. This section is largely irrelevant to the actual modes, so feel free to skip it.

In C++, there are three file classes, which are templates: basic_ifstream, basic_ofstream, and basic_fstream. They are typedefd on char to ifstream, ofstream, and fstream and on wchar_t to wifstream, wofstream, and wfstream. I refer to all of these classes as 'fstreams' (a subset of what I call 'iostreams'). I believe other people mean similar things for these terms, but I cannot recollect ever seeing them explicitly stated as such.

All of the open mode flags are defined in ios_base. This is not the same as the historical implementation (which had them defined in ios), but with the C++ standard (or perhaps earlier, let me know if you have specific information) the iostreams became template classes, except for ios_base (which was added), from which all the others are derived. Since ios is a typedef for basic_ios<char> (and this is not an accident), the flags are also in ios. Thus, it is not wrong to specify, for example, ios::out instead of ios_base::out, but it might be misleading.

Every stream has exactly one stream buffer associated with it. The stream buffer base class is basic_streambuf. Fstreams automatically define their own buffer (of type basic_filebuf) and pass it to the rest of the iostream hierarchy. They have a couple of methods that interface with this buffer's methods for opening and closing files.

This article is concerned with open, which is also the seat of the differences between the three file classes. It has a mode parameter, and its default value is ios_base::in for an basic_ifstream, ios_base::out for a basic_ofstream, and (ios_base::in | ios_base::out) for a basic_ifstream. The streams's open method calls the filebuf's open method. There


The Openmode Flags

A couple of ground points to cover. The ios_base class has a few types for flags and other specifiers. The one that concerns us is openmode which is an implementation defined bitmask type; app, ate, binary, in, out, and trunc are static constants of this type. (This means you can save a set of flags in your own variables for convenience.)

Mode Description
app each output is appended to the end of the file
ate (append to end) the file position is set to the end of the file when it is opened
binaryno text-stream ('\n') conversions are performed
in the file is opened for reading
out the file is opened for writing
trunc the file is created or its contents are erased before opening it

Specifying trunc is only valid for a file opened for output (it might be opened for input also, but at least output). Its effect is to delete the file and then create it again, or truncate it. If in is specified and the file does not exist, then the open fails unless trunc is also specified. If in is not specified and the file does not exist, then it is created. It is also an error to specify app with in or with trunc. (In other words, it is only valid to specify app with out and optionally with ate or binary.) Either in, out, or both must be specified.

For more information, open a C reference to fopen, combinations of these modes correspond directly to its mode parameter as follows. The following are also the only valid combinations. (Note that ate may be specified with any of these combinations, and its C equivalent is a call to fseek.)

Iostream Mode Combination fopen Mode
binaryinouttruncapp
x "w"
x x "a"
x x "w"
x "r"
x x "r+"
x x x "w+"
x x "wb"
x x x "ab"
x x x "wb"
x x "rb"
x x x "r+b"
x x x x "w+b"
Source: ISO/IEC 14882

The open Method

The open method is declared thus (basic_ifstream and basic_ofstream are not shown):

namespace std {
  template< class charT, class Traits >
  class basic_filebuf
  {
    //...
    basic_filebuf<charT,Traits>*
    open( const char* filename, ios_base::openmode mode );
    //...
  };
  template< class charT, class Traits >
  class basic_fstream : public basic_iostream< charT, Traits >
  {
    //...
    basic_fstream();
    explicit basic_fstream(
      const char* filename,
      ios_base::openmode mode = ios_base::in | ios_base::out
    );
    void open(
      const char* filename,
      ios_base::openmode mode = ios_base::in | ios_base::out
    );
    //...
  };
}

I have listed the constructors to show that you can default construct a fstream and open it later, or supply the same parameters when you initialize the object—whichever is up to you. It is also important to note that only null-terminated char arrays are used for the filename. There is not much more I can write, you just put the two together. Here are some examples.

#include <fstream>

const std::ios_base::openmode readwriteate
  = std::ios_base::in | std::ios_base::out | std::ios_base::ate;
  // input and output, seek to end of file if open is successful
  // file is NOT created if it does not exist

int main()
{
  using namespace std;

  ofstream log ( "myprogram.log", ios_base::out | ios_base::app );
    // output only, append mode
    // file IS created if it does not exist

  //...

  ifstream database;
  database.open( someparameter, ios_base::in | ios_base::binary );
    // input only, binary mode
    // file is NOT created if it does not exist

  //...

  fstream somefile ( "some.file", readwriteate );
    // use the compile-time constant readwriteate

  //...
  return 0;
}

Notes


References

(in alphabetical order)

Comments

Please send me any comments or corrections.


Last modified on September 24th, 2002.

Copyright 2002 Roger Pate, all rights reserved.
Email me if you want to duplicate this document.