📚 C Programming Tutorial

C Programming

Learn C programming concepts with simple explanations, examples and practical notes.

← Back to C Programming

Random access Files

Random access in C file handling

Random access in C allows us to move directly to a particular position in a file and read or modify data without processing all the preceding data.

The three important functions used for managing file positions are:

  • fseek() — moves the file position to a specified location.
  • ftell() — tells us the current file position.
  • rewind() — moves the file position back to the beginning of the file.

These functions are declared in the <stdio.h> header file.

What is random access?

Suppose a file contains 100 student records, and you want to access the 50th record.

  • Sequential access: Read records 1, 2, 3, and so on, until record 50 is reached.
  • Random access: Move directly to the location of record 50, provided the file uses a suitable record format.

The fseek() function

Definition: fseek() moves the file position indicator to a specified location in a file.

Syntax:

fseek(file_pointer, offset, origin);
Argument Meaning
file_pointer Pointer to the opened file
offset Number of bytes to move relative to the origin
origin Reference position from which the offset is measured

Values of origin

Constant Meaning
SEEK_SET Beginning of the file
SEEK_CUR Current file position
SEEK_END End of the file

Examples:

fseek(fp, 0, SEEK_SET);   // Beginning of file
fseek(fp, 5, SEEK_SET);   // 5 bytes from beginning
fseek(fp, 3, SEEK_CUR);   // 3 bytes forward from current position
fseek(fp, 0, SEEK_END);   // End of file

For ordinary binary files, offsets are commonly expressed in bytes. In text streams, portable seeking is more restricted: use offset 0 or a position returned by ftell() when using SEEK_SET, unless the implementation documents additional behavior.

The function returns 0 on success and a nonzero value on failure.

The ftell() function

Definition: ftell() returns the current file position indicator as a value of type long on success, or -1L if the position cannot be determined.

Syntax:

long position = ftell(fp);

For a binary file, this position is measured in bytes from the beginning of the file.

Example:

FILE *fp = fopen("data.bin", "rb");

if (fp != NULL)
{
    fseek(fp, 5, SEEK_SET);

    long position = ftell(fp);
    printf("Current position: %ld\n", position);

    fclose(fp);
}

If the seek succeeds, the output is:

Current position: 5

This means the file position is five bytes from the beginning. It does not mean five records have been read.

The rewind() function

Definition: rewind() moves the file position indicator to the beginning of the file.

Syntax:

rewind(fp);

Example:

rewind(fp);

After this statement, the next read operation starts at the beginning of the file.

Important points:

  • It does not delete or modify the file contents.
  • It has no return value.
  • It also clears the file's end-of-file and error indicators.

Complete C program using all three functions

This example creates a binary file containing ABCDEFGHIJ, moves to different positions, reads characters, and displays the current file position.

#include <stdio.h>

int main( )
{
    FILE *fp;
    char data[] = "ABCDEFGHIJ";
    char ch;
    long position;

    /* Create a binary file and write data */
    fp = fopen("data.bin", "wb");

    if (fp == NULL)
    {
        printf("Unable to create file.\n");
        return 1;
    }

    if (fwrite(data, 1, 10, fp) != 10)
    {
        printf("Error writing file.\n");
        fclose(fp);
        return 1;
    }

    fclose(fp);

    /* Open the file for reading */
    fp = fopen("data.bin", "rb");

    if (fp == NULL)
    {
        printf("Unable to open file.\n");
        return 1;
    }

    /* Move to byte position 4 */
    if (fseek(fp, 4, SEEK_SET) != 0)
    {
        printf("Seek failed.\n");
        fclose(fp);
        return 1;
    }

    position = ftell(fp);
    printf("Position after fseek(): %ld\n", position);

    ch = fgetc(fp);
    printf("Character read: %c\n", ch);

    position = ftell(fp);
    printf("Position after reading: %ld\n", position);

    /* Return to the beginning */
    rewind(fp);

    printf("Character after rewind(): %c\n", fgetc(fp));

    /* Move to the last byte */
    if (fseek(fp, -1L, SEEK_END) == 0)
    {
        printf("Last character: %c\n", fgetc(fp));
    }

    fclose(fp);

    return 0;
}

Output:

Position after fseek(): 4
Character read: E
Position after reading: 5
Character after rewind(): A
Last character: J

How does it work?

  • Writing: fwrite() stores the first ten characters in the binary file.
  • Seeking: fseek(fp, 4, SEEK_SET) moves the position to byte 4, where the character E is stored.
  • Checking the position: ftell(fp) returns 4, because the next read will start at byte 4.
  • Reading: fgetc(fp) reads E. The position advances to byte 5, so ftell(fp) now returns 5.
  • Rewinding: rewind(fp) moves back to byte 0. The next fgetc() reads A.
  • Accessing the end: fseek(fp, -1L, SEEK_END) moves to the final byte, which contains J.

Random access using student records

Random access becomes especially useful when each record has the same size.

Suppose every student record occupies sizeof(struct Student) bytes. To access a record by its zero-based index, use:

offset = index * record_size

For example, to access the fifth record, the zero-based index is 4.

#include <stdio.h>

struct Student
{
    int roll;
    char name[20];
    float marks;
};

int main( )
{
    FILE *fp;
    struct Student s;
    int recordNumber = 5;
    long offset;

    fp = fopen("students.dat", "rb");

    if (fp == NULL)
    {
        printf("Unable to open file.\n");
        return 1;
    }

    offset = (long)(recordNumber - 1) * sizeof(struct Student);

    if (fseek(fp, offset, SEEK_SET) != 0)
    {
        printf("Unable to locate record.\n");
        fclose(fp);
        return 1;
    }

    if (fread(&s, sizeof s, 1, fp) == 1)
    {
        printf("Roll: %d\n", s.roll);
        printf("Name: %s\n", s.name);
        printf("Marks: %.2f\n", s.marks);
    }
    else
    {
        printf("Record not found.\n");
    }

    fclose(fp);
    return 0;
}

Assumption: students.dat contains records written using the same structure layout, with records stored consecutively and no extra header or padding between records. This program uses one-based record numbering, so record 5 has index 4.

Quick comparison

Function Main purpose Example
fseek() Move to a chosen position fseek(fp, 4, SEEK_SET);
ftell() Find the current position ftell(fp);
rewind() Return to the beginning rewind(fp);