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
|