ZetCode

C fsetpos function

last modified April 6, 2025

File positioning is crucial for precise file operations in C programming. The fsetpos function allows you to set the file position indicator to a previously saved location. This tutorial explores fsetpos in depth, explaining its usage with practical examples. You'll learn how to combine it with fgetpos for reliable file navigation. Mastering these functions enables efficient random access file operations in your C programs.

What Is fsetpos?

The fsetpos function sets the file position indicator for a stream based on a position previously obtained with fgetpos. It takes a FILE pointer and a pointer to a fpos_t object as arguments. This function is particularly useful for large files where ftell might not work correctly. Always check the return value for errors. It returns zero on success and non-zero on failure.

Basic fsetpos Usage

This example demonstrates the fundamental usage of fsetpos to save and restore a file position.

basic_fsetpos.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("data.txt", "r");
    fpos_t position;
    
    if (fp == NULL) {
        perror("Error opening file");
        return 1;
    }

    // Get current position
    if (fgetpos(fp, &position) != 0) {
        perror("Error getting position");
        fclose(fp);
        return 1;
    }

    // Read some data
    char buffer[100];
    fgets(buffer, sizeof(buffer), fp);
    printf("First read: %s", buffer);

    // Restore position
    if (fsetpos(fp, &position) != 0) {
        perror("Error setting position");
        fclose(fp);
        return 1;
    }

    // Read again from original position
    fgets(buffer, sizeof(buffer), fp);
    printf("Second read: %s", buffer);

    fclose(fp);
    return 0;
}

This code opens a file and saves the initial position using fgetpos. After reading some data, it restores the position with fsetpos and reads the same data again. The fpos_t type stores the position information. Error checking is performed at each step to ensure proper operation.

Jumping to Specific Positions

Learn how to use fsetpos to jump to different positions in a file.

jump_positions.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("data.txt", "r");
    fpos_t positions[3];
    char buffer[100];
    int i;

    if (fp == NULL) {
        perror("Error opening file");
        return 1;
    }

    // Store three different positions
    for (i = 0; i < 3; i++) {
        fgetpos(fp, &positions[i]);
        fgets(buffer, sizeof(buffer), fp);
    }

    // Jump back to each position
    for (i = 0; i < 3; i++) {
        if (fsetpos(fp, &positions[i])) {
            perror("Error setting position");
            break;
        }
        fgets(buffer, sizeof(buffer), fp);
        printf("Position %d: %s", i, buffer);
    }

    fclose(fp);
    return 0;
}

This example stores three different file positions in an array of fpos_t objects. Later, it jumps back to each position using fsetpos and reads the data from those points. This technique is useful when you need to revisit multiple specific locations in a file. The code includes error handling for each position setting operation.

Working with Binary Files

See how fsetpos works with binary files for precise data access.

binary_fsetpos.c
#include <stdio.h>

struct Record {
    int id;
    double value;
};

int main() {
    FILE *fp = fopen("data.bin", "rb+");
    fpos_t pos;
    struct Record rec;

    if (fp == NULL) {
        perror("Error opening file");
        return 1;
    }

    // Save position of second record
    fseek(fp, sizeof(struct Record), SEEK_SET);
    fgetpos(fp, &pos);

    // Modify second record
    rec.id = 999;
    rec.value = 3.14159;
    fwrite(&rec, sizeof(struct Record), 1, fp);

    // Restore position and verify
    fsetpos(fp, &pos);
    fread(&rec, sizeof(struct Record), 1, fp);
    printf("Record: id=%d, value=%f\n", rec.id, rec.value);

    fclose(fp);
    return 0;
}

This example demonstrates fsetpos with binary file operations. It saves the position of the second record in a binary file, modifies it, then restores the position to verify the change. The fpos_t variable works seamlessly with binary files. This approach is ideal for database-like operations where precise record access is required.

Error Handling with fsetpos

Proper error handling is essential when working with file positions. This example shows robust error checking.

error_handling.c
#include <stdio.h>
#include <errno.h>

int main() {
    FILE *fp = fopen("nonexistent.txt", "r");
    fpos_t pos;

    if (fp == NULL) {
        perror("Initial open failed");
        return 1;
    }

    // Try to get position from invalid file
    if (fgetpos(fp, &pos) != 0) {
        perror("fgetpos failed");
        if (errno == EBADF) {
            printf("File descriptor is invalid\n");
        }
        fclose(fp);
        return 1;
    }

    // Try to set invalid position
    if (fsetpos(fp, &pos) != 0) {
        perror("fsetpos failed");
        if (errno == EINVAL) {
            printf("Invalid position specified\n");
        }
    }

    fclose(fp);
    return 0;
}

This code demonstrates comprehensive error handling for fsetpos and related functions. It checks return values and examines errno for specific error conditions. The example shows how to handle invalid file descriptors and position values. Proper error handling makes your file operations more reliable and easier to debug.

Large File Support

fsetpos is particularly useful for large files where ftell might not work correctly.

large_file.c
#include <stdio.h>
#include <stdlib.h>

int main() {
    FILE *fp = fopen("largefile.bin", "rb");
    fpos_t pos;
    long long file_size;

    if (fp == NULL) {
        perror("Error opening file");
        return 1;
    }

    // Move to end to get file size
    fseek(fp, 0, SEEK_END);
    fgetpos(fp, &pos);

    // Convert fpos_t to byte offset (platform-specific)
    // Note: This is just for demonstration - not portable
    file_size = *(long long *)&pos;
    printf("File size: %lld bytes\n", file_size);

    // Jump to middle of file
    fseek(fp, file_size/2, SEEK_SET);
    fgetpos(fp, &pos);

    // Process data from middle of file
    char buffer[1024];
    fread(buffer, sizeof(buffer), 1, fp);

    fclose(fp);
    return 0;
}

This example shows how fsetpos can handle positions in very large files. While the conversion of fpos_t to a numeric value is platform-specific, it demonstrates the concept. For truly portable code, use fgetpos and fsetpos without interpreting the fpos_t contents. This approach works reliably regardless of file size.

Combining with fgetpos

fsetpos is typically used with fgetpos to save and restore positions.

fgetpos_fsetpos.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("data.txt", "r");
    fpos_t start_pos, end_pos;
    char buffer[100];

    if (fp == NULL) {
        perror("Error opening file");
        return 1;
    }

    // Mark start position
    fgetpos(fp, &start_pos);

    // Read until empty line
    while (fgets(buffer, sizeof(buffer), fp)) {
        if (buffer[0] == '\n') {
            fgetpos(fp, &end_pos);
            break;
        }
    }

    // Process from start to empty line
    fsetpos(fp, &start_pos);
    while (fgetpos(fp, &start_pos), start_pos < end_pos) {
        fgets(buffer, sizeof(buffer), fp);
        printf("%s", buffer);
    }

    fclose(fp);
    return 0;
}

This example shows a practical use case for fgetpos and fsetpos together. It marks the start position, reads until an empty line, marks that position, then processes the section between the two positions. This pattern is useful for processing file segments. The positions are compared using their internal representation.

Text vs Binary Mode Considerations

Understand how text and binary modes affect fsetpos behavior.

text_binary.c
#include <stdio.h>

int main() {
    FILE *fp_text = fopen("text.txt", "r");
    FILE *fp_bin = fopen("text.txt", "rb");
    fpos_t pos_text, pos_bin;
    char ch;

    if (!fp_text || !fp_bin) {
        perror("Error opening files");
        return 1;
    }

    // Read first character in text mode
    ch = fgetc(fp_text);
    fgetpos(fp_text, &pos_text);

    // Read first character in binary mode
    ch = fgetc(fp_bin);
    fgetpos(fp_bin, &pos_bin);

    // Compare positions
    printf("Text mode position: %p\n", (void *)&pos_text);
    printf("Binary mode position: %p\n", (void *)&pos_bin);

    // Attempt cross-mode position setting (may fail)
    if (fsetpos(fp_text, &pos_bin) != 0) {
        printf("Cannot set text mode stream with binary position\n");
    }

    fclose(fp_text);
    fclose(fp_bin);
    return 0;
}

This example demonstrates that positions obtained in text mode may not be compatible with binary mode streams and vice versa. The code opens the same file in both modes, gets positions, and shows they're different. Attempting to use a binary mode position in a text mode stream typically fails. Always use positions with the same stream they were obtained from.

Best Practices for Using fsetpos

Source

C fsetpos Documentation

This tutorial has explored the fsetpos function in C, demonstrating its use for precise file positioning. From basic usage to advanced scenarios with large files, these examples provide a solid foundation for file handling in your C programs.

Author

My name is Jan Bodnar, and I'm a dedicated programmer with a deep passion for coding. Since 2007, I've been sharing my expertise through over 1,400 articles and 8 e-books. With more than a decade of teaching experience, I strive to make programming accessible and engaging.

List C Standard Library.