Reading data from a text file that is then examined or manipulated in some way is known as file processing. When reading a collection of data or processing the contents of a file, we need a properly constructed input loop:
// priming read
while( condition ) {
//process data
//modification read
}
Remember, the condition in the input loop tests for or compares against the sentinel value, which indicates that we have finished reading data or reached the end of the input collection.
End of File
When reading and processing a file, the sentinel value is typically a test to determine if the end of file has been reached. In C, the feof
function is used for this purpose
// priming read
while( !feof(infile) ) {
. . .
// modification read
}
The feof
returns true if the end of file was reached during the last input operation (i.e. using either fscanf
or fgetc
). Note, that you must first try reading data from the input file before testing if the end of file was reached. Thus, the need for a priming read.
Processing Data
Consider a text file that contains a set of exam grades specified as integers stored one per line
Suppose we want to compute the average exam grade for a collection of grades stored in a text file. This task can be accomplished using the following code segment:
int grade;
int sum = 0;
int count = 0;
fscanf(infile, "%d", &grade); // priming read
while(!feof(infile)) { // test for end of file
sum = sum + grade;
count = count + 1;
fscanf(infile, "%d", &grade); // modification read
}
float avg = sum / float(count);
printf("Average exam grade = %0.2f\n", avg);
Sometimes, the text file may contain records of information in which each record contains multiple fields of information. For example, suppose the data file contained both the id number and the exam grade for each student in the following format:
245 85
189 90
175 89
206 75
122 100
284 98
111 86
Since each record consists of two fields, only the first field has to be read before testing for the end of file. He we would read the student id number as the priming read, then test for the end of file. If the end of file was not reached, we then read the rest of the record before processing the data. These steps are illustrated in the following code segment:
int grade, id;
int sum = 0;
int count = 0;
fscanf(infile, "%d", &id); // priming read - read first record field (id num)
while(!eof(infile)) {
fscanf(infile, "%d", &grade); // read the rest of the record
sum = sum + grade;
count = count + 1;
fscanf(infile, "%d", &id); // modification read
}
Remember, the modification read should always be the same operation as the priming read. Thus, we only read the id number at the bottom of the loop.
Processing Characters
Sometimes, you may want to read the text from the file as characters instead of numerical data. The fscanf
function, however, as indicated in the previous section, skips over white space characters when reading individual characters from the file. If you need to read all characters, including white space characters, then you must use the fgetc
function instead of the fscanf
function. The fgetc
function takes the file variable as an argument and returns the next character in the file without skipping over any other characters
int ch;
ch = fgetc(infile);
This function is typically used within a loop to read multiple characters from a text file. In the following program, we read the individual characters from the text file and simply display them to the terminal.
Program Listing
/* showfile.cc
*
* Reads the contents of a text file and prints the contents to the terminal.
*/
#include <stdio.h>
int main()
{
FILE *infile;
// Open the file and verify it was opened.
infile = fopen("document.txt", "r");
if(!infile) {
printf("Error: the input file could not be opened.\n");
exit(1);
}
// Read the entire contents and print it to the terminal.
int ch;
ch = fgetc(infile); // priming read
while(!feof(infile)) { // test for end of file
printf("%c", ch);
ch = fgetc(infile); // modification read
}
// Close the file
fclose(infile);
}
|