CFile Positioning (fseek/ftell)

File Positioning (fseek/ftell)

Every open file has a current position — the offset, in bytes, where the next read or write will happen. Sequential I/O functions like fgets and fread automatically advance this position as they consume data; fseek, ftell, and rewind let you inspect and control it directly, enabling random access instead of a strictly front-to-back read.

ftell() — Where Am I?

C
long ftell(FILE *fp);

ftell returns the current byte offset within the file, or -1L on failure. It is the read-only counterpart to fseek.

fseek() — Jump to a Position

C
int fseek(FILE *fp, long offset, int whence);

whence value

Meaning of offset

SEEK_SET

Absolute position, measured from the start of the file

SEEK_CUR

Relative position, measured from the current position

SEEK_END

Relative position, measured from the end of the file (often used with a negative offset)

fseek returns 0 on success and nonzero on failure. Combined with the three whence constants, it can move forward, backward, or jump straight to an absolute byte offset.

rewind() — Back to the Start

rewind(fp) is a convenience shortcut, equivalent to fseek(fp, 0L, SEEK_SET) — but it also clears the file's error and end-of-file indicators, which plain fseek does not do.

Worked Example: Finding a File's Size

A common trick for finding how big a file is (in bytes) is to seek all the way to the end, ask ftell for the current position (which is now the total size), then seek back to the beginning before doing any real reading.

C
#include <stdio.h>

int main(void)
{
    FILE *fp = fopen("data.bin", "rb");
    if (fp == NULL) {
        printf("Could not open file.\n");
        return 1;
    }

    fseek(fp, 0L, SEEK_END);   /* jump to the very end */
    long size = ftell(fp);    /* current position == total byte size */

    rewind(fp);                /* jump back to the start for real reading */

    printf("File size: %ld bytes\n", size);

    fclose(fp);
    return 0;
}
File size: 4096 bytes
Random Access to Binary Records

Because fseek can jump to any absolute offset, it makes it possible to treat a binary file as an array of fixed-size records on disk — jump directly to record number N by seeking to N * sizeof(Record), without reading through every record before it.

C
typedef struct {
    char name[20];
    int score;
} Player;

Player readPlayerAt(FILE *fp, int index)
{
    Player p;
    fseek(fp, (long) index * sizeof(Player), SEEK_SET);
    fread(&p, sizeof(Player), 1, fp);
    return p;
}

/* readPlayerAt(fp, 2) jumps straight to the third Player record
   without reading records 0 and 1 first. */
Note
This random-access pattern is the basis of simple record-based file formats and lightweight database-like structures — as long as every record has the same fixed size, its position can always be computed directly instead of scanned for.
  • ftell — read the current position

  • fseek — jump to an absolute or relative position

  • rewind — shortcut back to byte 0, also clears error/EOF flags