Working with Text Files Longer than a Single Line

Unless your program also created the file it’s reading, you have no guarantee how must text lurks inside. It could be a single character or the entire works of Shakespeare. Dealing with an unknown quantity of text it a file-reading challenge.

To write an unknown quantity of text is really no big deal: You keep using file-output functions, such as fprintf() or fputs() until you’ve sent away as much text as desired. Close the file. You’re done.

For reading an unknown quantity of text, start with a text file. For the sample code in this Lesson, I’ve used the declaration.txt file, which you can obtain by clicking the link.

To start, the file is opened in "r", read mode.

I recommend reading the file by chunks of text. The fgets() function is up the task. It requires a char buffer to store text. See last week’s Lesson for an example, though that example reads only one line from the file.

The fgets() function is called repeatedly until the EOF condition is returned. This flag is set by the operating system when the last byte from a file has been read. To detect this condition, use the feof() function. When feof() returns a non-zero value, the EOF has been encountered.

The last step is to close the file.

#include <stdio.h>

int main()
{
    const char filename[] = "declaration.txt";
    const int bufsize = 64;
    char buffer[bufsize];
    FILE *f;

    /* open the file for reading */
    f = fopen(filename,"r");
    if( f == NULL )
    {
        fprintf(stderr,"Error opening %s\n",filename);
        return(1);
    }

    /* read all the text */
    while( !feof(f) )
    {
        fgets(buffer,bufsize,f);
        printf("%s",buffer);
    }

    /* close the file */
    fclose(f);

    return(0);
}

A while loop at Line 19 checks for the feof() condition on file handle f. The ! (not) is used because feof() returns zero until the actual end-of-file is encountered. So the loop spins, reading one line or 64 characters of text from the file and printing that buffer. When the EOF is found, the loop stops and the file is closed.

The file outputs the entire contents of the declaration.txt file. You could make the code more efficient by increasing the buffer size. For example, if the operating system reads files in 2K chunks, you could change the buffer size of 2048, but on modern computers the difference wouldn’t be that noticeable.

Files can also be read one byte a time, which allows for tighter code:

#include <stdio.h>

int main()
{
    const char filename[] = "declaration.txt";
    FILE *f;
    int ch;

    /* open the file for reading */
    f = fopen(filename,"r");
    if( f == NULL )
    {
        fprintf(stderr,"Error opening %s\n",filename);
        return(1);
    }

    /* read all the text */
    while(1)
    {
        ch = fgetc(f);
        if( ch == EOF)
            break;
        putchar(ch);
    }

    /* close the file */
    fclose(f);

    return(0);
}

The while loop at Line 19 is endless. At Line 20, fgetc() fetches a single character from the open file f and stores it in variable ch. At Line 21, variable ch is tested for the EOF flag, which breaks the loop. Otherwise, the character is output at Line 23.

The approach of reading a file one character at a time is best for immediate output. Otherwise, when you must examine the file’s text, using fgets() to store text in a buffer is a better choice.

For next week’s Lesson, I cover writing values to a file.

Leave a Reply