File manipulation

Aims

To enable students to:

  1. discuss data file streams

  2. open and close files

  3. write to and read from files

Discuss data file streams

Programs written so far have interacted with the user by passing data to the cout object using the insertion operator << and retrieving data from the cin object via >> (the extraction operator). Items processed by cout are written to stdout (usually a monitor), while cin uses stdin (usually a keyboard).

Large programs frequently wish to record internal status information such as a trace of all the functions entered and left by the program during its operation. Unfortunately if they recorded this information using the cout object the user display would be interrupted with status messages. C++ supplies another output object called cerr to which error and status messages should be sent. Data sent to cerr is written to stderr, although this is also usually a monitor and consequently interferes with the user display it is possible for stderr to be changed so that it points to another device.

The cerr object is used in the same way as cout. The following code displays a message on the stdout and stderr devices:

void main ()
{
    cout << "Hello"; // Displays "Hello" on stdout

    cerr << "Hello"; // Displays "Hello" on stderr
}

Besides using the standard input and output objects cin, cout and cerr to access and store data it is possible for programs to use their own data file streams (files). If a program wishes to permanently store information to work on at a later date then it must use its own files.

For compatibility with standard C programs, C++ fully supports the standard I/O functions (fopen, fwrite, fclose, etc.) originally shipped with C.

Open and close files

To gain access to your own files the header file fstream.h must be included within each source file that accesses it. As fstream.h includes iostream.h there is no need to include the latter header file in source files that reference the former. To open a file for output an instance of the class ofstream is instantiated. The constructor for ofstream takes the following form:

ofstream( const char* szName, int nMode = ios::out, int nProt = filebuf::openprot );

where

  • szName is the name of the file to be opened.

  • nMode is an integer that contains mode bits defined as ios enumerators that can be combined with the bitwise OR ( | ) operator. The nMode parameter must have at least one of the following values:

    • ios::app - The function performs a seek to the end of file. When new bytes are written to the file, they are always appended to the end, even if the position is moved with the ostream::seekp function.

    • ios::ate - The function performs a seek to the end of file. When the first new byte is written to the file, it is appended to the end, but when subsequent bytes are written, they are written to the current position.

    • ios::in - The original file (if it exists) will not be truncated, the output pointer is position at the start of the file.

    • ios::out - The file is opened for output (implied for all ofstream objects).

    • ios::trunc - If the file already exists, its contents are discarded. This mode is implied if ios::out is specified and ios::ate, ios::app, and ios:in are not specified.

    • ios::nocreate - If the file does not already exist, the function fails.

    • ios::noreplace - If the file already exists, the function fails.

    • ios::binary - Opens the file in binary mode (the default is text mode).
  • nProt is the file protection specification defined as filebuf enumerators that can be combined with the bitwise OR ( | ) operator. The nProt parameter must have at least one of the following values:

    • filebuf::sh_compat - Compatibility share mode.

    • filebuf::sh_none - Exclusive mode; no sharing.

    • filebuf::sh_read - Read sharing allowed.

    • filebuf::sh_write - Write sharing allowed.

To open an output file called out.txt the code below is used. If the file does not yet exist it is created, otherwise the existing file is opened and its contents destroyed.

#include <fstream.h>

void main ()
{
    ofstream ofOutputFile ("out.txt"); // Open a file call out.txt
    ofOutputFile << "Hello"; // Write "Hello" to the file out.txt  
}

To open a file for input n instance of the class ifstream must be created. The constructor for ifstream takes the following form:

ifstream( const char* szName, int nMode = ios::in, int nProt = filebuf::openprot );

where

  • szName is the name of the file to be opened during construction.

  • nMode is an integer that contains mode bits defined as ios enumerators that can be combined with the bitwise OR ( | ) operator. The nMode parameter must have at least one of the following values:

    • ios::in - The file is opened for input (default).

    • ios::nocreate - If the file does not already exist, the function fails. Note that the ios::nocreate flag is necessary if you intend to test for the file's existence (the usual case).

    • ios::binary - Opens the file in binary mode (the default is text mode).

    • nProt is the file protection specification defined as filebuf enumerators that can be combined with the bitwise OR ( | ) operator. The nProt parameter must have at least one of the following values:

    • filebuf::sh_compat - Compatibility share mode.

    • filebuf::sh_none - Exclusive mode - no sharing.

    • filebuf::sh_read - Read sharing allowed.

    • filebuf::sh_write - Write sharing allowed.

To open an input file called in.txt the code below is used - note if the file does not yet exist it is created.

#include <fstream.h>

void main ()
{
    ifstream ifInputFile ("in.txt); // Open a file call in.txt
}

Once a file has been finished with it is good practice to close it using the member function close (present in both classes). Note, the destructor will close the file when the object is destroyed if the program did not explicitly call close first.

Besides reading and writing to your own disk files the stream library provides access to several system devices via the following names:

Named passed to constructor    Device opened
AUX Same as COM1
COM1, COM2, COM3 or COM4 Serial port number 1, 2, 3 or 4
CON Console (monitor and keyboard)
LPT1, LPT2 or LPT3 First, second or third parallel port
PRN Same as LPT1

Write to and read from files

Besides the insertion and extraction operator objects of type ifstream and ofstream support several member functions to interact with the underlying file.

Objects of type ofstream support several functions to write data to files. The function put takes a single character and places it on the output stream, as in:

void main ()
{
    ofstream ofOutputFile ("out.txt"); // Opens a file called out.txt

    ofOutputFile.put ('a'); // Writes lower case a to out.txt
}

The function write takes a pointer to an array of characters and the number of bytes to write allowing blocks of data to be easily dumped to disk. Remember by default files are opened in text mode which means the ofstream object will translate certain character combinations, for example the newline character (ascii10) will result in a carriage-return and newline character (ascii 13 and 10) being written to disk), to avoid this open the file in binary mode. Example showing the use of write:

void main ()  
{
    char szArray [10] = "Hellon"; // Set up a buffer in memory

    ofstream ofOutputFile ("out.txt"); // Opens a file called out.txt

    ofOutputFile.write (szArray, strlen (szArray)); // Write memory buffer to out.txt
}

Objects of type ifstream have several member methods to access information stored within the file they represent.

The function get permits the next character to be read from the input stream, as in:

void main ()
{
    char cInput; // Variable to hold character read from file

    ifstream ifInputFile ("in.txt"); // Open file in.txt for input

    ifInputFile.get (cInput); // Get the next character from in.txt
}

The function get has been overloaded to permit multiple characters to be fetched simultaneously. The caller provides the function with a pointer to a block of memory and the number of bytes to read:

void main ()
{
    char szString [128]; // Array to hold data read from file

    ifstream ifInputFile ("in.txt"); // Open file in.txt for input

    ifInputFile.get (szString, sizeof (szString)); // Fill the array with characters
}

This version of get will read characters from the file until the specified number have been fetched or a new line character has been encountered. It then writes a NULL character to the buffer provided. The get function does not extract the new line from the input stream, if you were to call it a second time the function will return immediately without reading any further data as the terminating character is met immediately. To get around this the ifstream class provides another function getline that behaves exactly like get except that it extracts the new line character from the input stream and throws it away (the character is not stored in the receiving buffer).

Download