Using fseek and ftell for Random File Access in C

In C file handling, fseek and ftell are essential standard library functions that enable random access, allowing developers to read or write data at any specific position within a file rather than processing it sequentially from start to finish. This article explains the core purpose of both functions, how their parameters control the file position indicator, and how they work together to navigate files, retrieve current offsets, and determine total file sizes.

Understanding Random Access

By default, file operations in C (such as fread, fwrite, fgetc, or fgets) operate sequentially. Every read or write automatically advances the internal file position indicator by the number of bytes processed. In many applications—such as database engines, indexed file readers, or media decoders—reading through gigabytes of data sequentially to reach a specific record is inefficient. Random file access solves this problem by directly jumping to the required byte offset.

The Purpose of fseek

The fseek function repositions the file position indicator associated with a given file stream. Its function prototype is defined in <stdio.h> as:

int fseek(FILE *stream, long offset, int whence);
  • stream: A pointer to the open FILE object.
  • offset: A signed integer representing the number of bytes to shift the position indicator relative to the reference point defined by whence. A positive value moves forward; a negative value moves backward.
  • whence: The reference point from which the offset is applied. The C standard defines three constants for this argument:
    • SEEK_SET: The beginning of the file.
    • SEEK_CUR: The current position of the indicator.
    • SEEK_END: The end of the file.

fseek returns 0 upon success and a non-zero value if an error occurs, such as attempting an invalid seek operation on a non-seekable stream (like a network socket or standard input).

The Purpose of ftell

The ftell function determines the current value of the file position indicator. Its prototype is:

long ftell(FILE *stream);

For binary streams, ftell returns the exact number of bytes from the beginning of the file to the current position. For text streams, the return value is an implementation-defined token that can still be passed to fseek with SEEK_SET to return to that exact position. If an error occurs, ftell returns -1L and sets errno.

ftell is critical for bookmarking locations in a file before navigating away, logging positions, or computing the sizes of dynamically allocated buffers needed to store file contents.

Working Together: Common Use Cases

fseek and ftell are frequently used in combination to perform operations that sequential file streams cannot natively handle:

  1. Determining File Size: Moving the indicator to the end of the file with fseek(fp, 0, SEEK_END) and immediately calling long size = ftell(fp) provides the complete byte size of the file. Afterward, calling fseek(fp, 0, SEEK_SET) (or rewind(fp)) resets the indicator so normal processing can begin.
  2. Accessing Fixed-Width Records: If a binary file contains uniform structs of size N, the program can directly access record i by computing the byte offset (i * sizeof(struct Record)) and calling fseek(fp, offset, SEEK_SET) before reading.
  3. In-Place File Updates: When an entry needs modification, fseek allows the program to jump directly over existing bytes, overwrite the data with fwrite, and maintain the surrounding file structure without rewriting the entire file.