Abuse the File Position Indicator

Files can be read sequentially or you can hop around, reading this chunk or that chunk, which is how random file access works. Internally, however, it’s all just file access. The difference between sequential and random file access is how the file position indicator is abused.

The traditional file position indicator abuse functions are ftell(), fseek(), and rewind(). I covered fell() in the September 12 Lesson, and rewind() was covered last week. Now it’s time for fseek().

The fseek() function is the random access function. For example, when reading structures to a file you can use fseek() to set the file position indicator to read a specific structure in the file. The fread() function fetches the structure’s chunk-o-info. Here’s the format for fseek():

fseek(handle,offset,whence)

handle is the file pointer for an open file.

offset is a long int value for the number of bytes relative to the whence position, the spot where the file position indicator is moved. This value can be positive or negative.

whence is one of three constants, SEEK_SET, SEEK_CUR, or SEEK_END for the start of the file, current file indicator position, or the end of the file, respectively.

In the following code, fseek() reads and outputs the last 10 characters of the file gettysburg.txt and then reads and outputs the first 10 characters of the file.

#include <stdio.h>
int main()
{
    FILE *fh;
    int c,x;

    /* open the file */
    fh = fopen("gettysburg.txt","r");
    if(fh == NULL)
    {
        perror("Unable to open file\n");
        return(1);
    }

    /* read the last 10 bytes */
    printf("Last 10 bytes: ");
    fseek(fh,-10,SEEK_END);
    while( (c=fgetc(fh)) != EOF)
        putchar(c);

    /* read the first 10 bytes */
    printf("First 10 bytes: ");
    fseek(fh,0,SEEK_SET);
    for(x=0;x<10;x++)
        putchar(fgetc(fh));
    putchar('\n');

    fclose(fh);

    return(0);
}

The fseek() function at Line 18 positions the file indicator to 10 bytes (characters) before the EOF. The value -10 and SEEK_END set that position.

At Line 24, the fseek() function is pinch-hitting for rewind(). In effect, the fseek() function in that specific format works the same as rewind().

Here's sample output:

Last 10 bytes: d equal.

First 10 bytes: Four score

Given what you know about fseek(), how would you concoct code to read the middle 10 bytes of a file?

The fseek() function doesn't have a whence position for the file's center. So how could you determine the file's overall size, split that in two, and then position the file indicator to read the middle 10 bytes of a file?

Yes, this is a Lesson, not an Exercise, so while you could rush off and attempt to figure out a solution on your own (and thank you for trying), my solution is this:

Set the file position indicator to the end of the file with fseek(fh,0,SEEK_END), then use ftell() to get that position value. Divide it by 2, then use fseek() to set the center location and read 10 characters.

Here's the chunk of code I added to the above listing at Line 29, also after declaring an int variable middle:

    /* read the middle 10 bytes */
    fseek(fh,0,SEEK_END);
    middle = ftell(fh) / 2;
    fseek(fh,middle-5,SEEK_SET);
    printf("Middle 10 bytes: ");
    for(x=0;x<10;x++)
        putchar(fgetc(fh));
    putchar('\n');

Click here to download or view the modified source code.

Here is the new output:

Last 10 bytes: d equal.

First 10 bytes: Four score
Middle 10 bytes: tion, conc

The true power of fseek(), however, is in its capability to fetch a file organized into specific chunks, i.e., random access. I'll demonstrate that technique in next week's Lesson.

Leave a Reply