Absolute Beginners C++


Lesson 12 - Files

12.1 Output to a file

// ex12-1 - output to a file
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
int main()
{
    // try to open output file list.txt
    ofstream output("list.txt");
    if (output.fail()) {
        cout << "error: could not open 'list.txt'"
             << endl;
        exit(1);        // abort program
    }
    // write some stuff
    for (int i=1;i<=10;i++) 
        output << setw(8) << i 
               << setw(8) << i*i << endl;
    // close the output file
    output.close();
    return(0);
}
ex12-1
type list.txt
      1      1
      2      4
      3      9
etc
Example ex12-1 shows how a disk file can be opened and written to.  This program reports the integers from 1 to 10 and their squares, but instead of reporting these to the screen saves them in a text file called 'list.txt'.  Once the program has run, you can investigate the file list.txt to see its contents.  The program includes the standard software component <fstream> which gives character stream access to files.  To access a file we need an object to 'stand for' a channel connected to the file in our program: this is the object called 'output' which is declared of being of type 'ofstream', namely an output file stream channel.  The declaration 'ofstream output('list.txt');' performs a number of functions: it declares a variable 'output' of type ofstream, it connects that stream to the file list.txt, and if that file already exists it deletes any existing contents of that file.  Since there are a number of circumstances when these operations might fail, it is imperative to test that they have completed successfully.  We can do this by testing the 'fail()' property of the output channel object.  If the output channel has not been opened successfully, the fail() method will return true and you can take appropriate action.  Here we report a message to the screen and end the program.  The method used here to end the program is to call a function called 'exit()' which stops execution immediately causing the main function to return with the integer value provide as an argument.  In this case we could have called 'return()' instead, but the advantage of exit() is that it can be called from anywhere - even inside a sub function of your program.  Notice that once the output channel is open, we can use it in the same way that we have used the cout object to print values.  Finally, we must close the channel before the program exits to ensure that all operations on the file are finished.  We do this by calling the close() method of the ofstream object.

12.2 Reading list of values

// ex12-2 - read values from file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
    // try to open input file list.txt
    ifstream input("list.txt");
    if (input.fail()) {
        cout << "error: could not find file 'list.txt'" 
             << endl;
        exit(1);    // abort program
    }
    // read the file as list of integers and sum them
    int sum=0;
    int val;
    input >> val;
    while (!input.eof()) {
        sum += val;
        input >> val;
    }
    // report sum
    cout << "Sum=" << sum << endl;
    // close the input file
    input.close();
    return(0);
}
ex12-2
Sum=440
Example ex12-2 is the mirror of the last example: it opens a file 'list.txt' for reading and processes the numbers it finds in the file.  To read from a file we need an object to stand for the input channel connected to the file, and here this is of  type 'ifstream', an input file stream channel.  The declaration 'ifstream input('list.txt');' declares an object called input of type ifstream which is connected to the disk file list.txt.  This statement creates the channel and attaches it to a file list.txt which must already exist.  Again, these operations might fail for a number of reasons (e.g. the file does not exist) and so we must check that the channel was opened sucessfully by testing the fail property of the ifstream object through the fail() method.  Once the channel is open, we can read values through the channel in the same way as we read values using cin.  In the example, we simply sum all the integer values in the file.  The program reports the sum and closes the file channel. 

12.3 Copying a file character by character

 // ex12-3 - read and write character by character
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// report error and die
void error(string messg)
{
    cout << "Error: " << messg << endl;
    exit(1);
}
// main program
int main(int argc,char *argv[])
{
    // check program arguments
    if (argc!=3)
        error("usage: ex12-3 in.txt out.txt");
    // try to open input
    ifstream input(argv[1]);
    if (input.fail())
        error("could not open input file");
    // try to open output
    ofstream output(argv[2]);
    if (output.fail())
        error("could not open output file");
    // copy the file character by character
    int c = input.get(); // get character
    while (!input.eof()) {
        output.put(c); // put character
        c = input.get(); // get character
    }
    // close the files
    input.close();
    output.close();
    return(0);
}
ex12-3 list.txt out.txt
Example 12-3 shows how we can choose to read and write files character by character rather than value by value.  The advantage of this is that all files are sequences of characters, so we can process any file using this method.  To write a general purpose copying program, we need to accept the names of the files on the command line as program arguments.  We simply assume that the program is run with two arguments where the first is the name of the file to read, and the second is the name of the file to write.  To read a single character from the input stream, we can use the ifstream method function 'get()'.  Any single character can always be stored in an integer, so we use an integer 'c' to hold the character itself.  To write a single character to the output stream, we use the ofstream method 'put()' which takes an integer argument containing the character to be written.  To copy until the end of the input file, we use a while loop, with the condition that the input stream is not at the end-of-file by testing '!input.eof()'.
This example also demonstrates a useful function, error, which is used to report a message and terminate the program if something goes wrong.

12.4 Exercises

a. Write a program (decimate.cpp) that reads a list of numbers from a given file (specified on command line) and reports every tenth number.

b. Write a program (wcount.cpp) that takes a text file and reports the number of lines, words and characters in the file. Define a word as a string of alphanumeric characters terminated by a non-alphanumeric character. To test if a character is alphanumeric, you might find the function isalnum()defined in "ctype.h" useful. To test if a character represents the end-of-line character, test its equality against '\n'.

wcount wcount.cpp
wcount.cpp contains: 41 lines, 111 words, 781 chars.
c. Write a program (uniq.cpp) that takes two files each containing a list of words and which reports the words found in file2 which were not found in file1, as in:
uniq dict.txt file.txt
Words in file.txt not found in dict.txt:
banana
uniquely
serendipity


© 1999 Mark Huckvale University College London