ZetCode

C fgetpos 函数

最后修改日期:2025 年 4 月 6 日

在 C 编程中处理文件时,文件位置处理至关重要。fgetpos 函数有助于准确跟踪和恢复文件位置。本教程将详细介绍 fgetpos,涵盖其语法、用法和实际应用。您将学习如何高效地保存和恢复文件位置,确保程序中精确的文件操作。

什么是 fgetpos?

C 中的 fgetpos 函数将流的当前文件位置存储在 fpos_t 对象中。它接受两个参数:一个文件指针和一个指向 fpos_t 变量的指针。此函数对于 ftell 可能无法提供足够范围的大文件特别有用。始终检查返回值——零表示成功,非零表示错误。

基本 fgetpos 用法

此示例演示了 fgetpos 保存文件位置的基本用法。

basic_fgetpos.c
#include <stdio.h>

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

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

    printf("Position saved successfully\n");
    fclose(fp);
    return 0;
}

在这里,我们打开一个文件并声明一个 fpos_t 变量来存储位置。fgetpos 保存文件指针的当前位置。如果成功,它返回 0;否则,它返回非零并设置 errno。这个基本示例展示了在使用 fgetpos 时如何正确检查错误。

保存和恢复位置

此示例演示了如何使用 fgetpos 保存位置,然后恢复到该位置。

save_restore.c
#include <stdio.h>

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

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

    // Read first line
    fgets(buffer, sizeof(buffer), fp);
    printf("First line: %s", buffer);

    // Save position after first line
    if (fgetpos(fp, &saved_pos)) {
        perror("Error saving position");
        fclose(fp);
        return 1;
    }

    // Read next line
    fgets(buffer, sizeof(buffer), fp);
    printf("Second line: %s", buffer);

    // Return to saved position
    if (fsetpos(fp, &saved_pos)) {
        perror("Error restoring position");
        fclose(fp);
        return 1;
    }

    // Read again from saved position
    fgets(buffer, sizeof(buffer), fp);
    printf("Re-read second line: %s", buffer);

    fclose(fp);
    return 0;
}

此程序演示了在读取第一行后保存文件位置,然后读取第二行,最后返回到保存的位置以重新读取第二行。对于大文件,fgetpos/fsetpos 对比 ftell/fseek 更可靠。

多个位置书签

此示例演示了如何使用 fgetpos 保存文件中的多个位置。

multiple_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;
    }

    // Save three different positions
    for (i = 0; i < 3; i++) {
        fgets(buffer, sizeof(buffer), fp);
        if (fgetpos(fp, &positions[i])) {
            perror("Error saving position");
            fclose(fp);
            return 1;
        }
    }

    // Jump between saved positions
    for (i = 2; i >= 0; i--) {
        if (fsetpos(fp, &positions[i])) {
            perror("Error restoring position");
            fclose(fp);
            return 1;
        }
        fgets(buffer, sizeof(buffer), fp);
        printf("Position %d: %s", i, buffer);
    }

    fclose(fp);
    return 0;
}

此程序在 fpos_t 结构数组中保存三个不同的文件位置。然后,它演示了如何以相反的顺序跳转到这些保存的位置。当您需要重新访问文件中的多个特定位置时,此技术非常有用。

二进制文件位置处理

此示例演示了 fgetpos 在二进制文件中的用法。

binary_position.c
#include <stdio.h>

int main() {
    FILE *fp = fopen("data.bin", "rb");
    fpos_t position;
    int value;

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

    // Read first integer
    fread(&value, sizeof(int), 1, fp);
    printf("First value: %d\n", value);

    // Save position
    if (fgetpos(fp, &position)) {
        perror("Error saving position");
        fclose(fp);
        return 1;
    }

    // Read next integer
    fread(&value, sizeof(int), 1, fp);
    printf("Second value: %d\n", value);

    // Return to saved position
    if (fsetpos(fp, &position)) {
        perror("Error restoring position");
        fclose(fp);
        return 1;
    }

    // Read again from saved position
    fread(&value, sizeof(int), 1, fp);
    printf("Re-read second value: %d\n", value);

    fclose(fp);
    return 0;
}

此示例展示了 fgetpos 如何处理二进制文件。该程序从二进制文件中读取整数,保存一个位置,并演示位置恢复。二进制模式操作通常需要精确的位置处理,这使得 fgetpos 在这些场景中特别有价值。

fgetpos 的错误处理

此示例侧重于在使用 fgetpos 时进行正确的错误处理。

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

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

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

    // Try to get position from invalid file
    if (fgetpos(fp, &position)) {
        printf("fgetpos failed with errno: %d\n", errno);
        perror("Detailed error");
        fclose(fp);
        return 1;
    }

    fclose(fp);
    return 0;
}

此示例演示了如何处理使用 fgetpos 时的错误。它展示了如何检查返回值以及使用 errnoperror 获取详细的错误信息。正确的错误处理对于处理文件位置以确保程序的健壮性至关重要。

大文件支持

此示例展示了 fgetpos 如何处理超出 ftell 范围的大文件。

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

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

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

    // Seek to a large position
    if (fseek(fp, 2147483647L, SEEK_SET)) {
        perror("Error seeking in file");
        fclose(fp);
        return 1;
    }

    // Save position with fgetpos
    if (fgetpos(fp, &position)) {
        perror("Error saving position");
        fclose(fp);
        return 1;
    }

    // Compare with ftell
    ftell_result = ftell(fp);
    if (ftell_result == -1L) {
        perror("ftell failed");
    } else {
        printf("ftell result: %ld\n", ftell_result);
    }

    printf("Position saved with fgetpos successfully\n");
    fclose(fp);
    return 0;
}

此示例演示了 fgetpos 相对于 ftell 处理大文件的优势。虽然 ftell 在非常大的文件位置(超过 LONG_MAX)时可能会失败,但 fgetpos 可以正确处理它们。这使得 fgetpos 对于处理大于 2GB 的文件至关重要。

使用 fgetpos 进行随机访问

此示例演示了如何使用 fgetposfsetpos 实现文件随机访问。

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

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

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

    // First pass: count lines and save positions
    while (fgets(buffer, sizeof(buffer), fp) {
        line_count++;
    }

    positions = malloc(line_count * sizeof(fpos_t));
    if (positions == NULL) {
        perror("Memory allocation failed");
        fclose(fp);
        return 1;
    }

    rewind(fp);
    for (i = 0; i < line_count; i++) {
        if (fgetpos(fp, &positions[i])) {
            perror("Error saving position");
            free(positions);
            fclose(fp);
            return 1;
        }
        fgets(buffer, sizeof(buffer), fp);
    }

    // Second pass: access lines in random order
    for (i = line_count-1; i >= 0; i--) {
        if (fsetpos(fp, &positions[i])) {
            perror("Error restoring position");
            free(positions);
            fclose(fp);
            return 1;
        }
        fgets(buffer, sizeof(buffer), fp);
        printf("Line %d: %s", i+1, buffer);
    }

    free(positions);
    fclose(fp);
    return 0;
}

此程序演示了对文件内容的高级随机访问。它首先扫描文件以计算行数并保存其位置,然后以相反的顺序访问它们。此技术对于实现对文件内容的高效随机访问而不将整个文件加载到内存中非常有用。

使用 fgetpos 的最佳实践

来源

C fgetpos 文档

本教程深入探讨了 fgetpos 函数,展示了它在文件位置处理中的重要性。从基本用法到高级随机访问模式,fgetpos 为 C 程序中的健壮文件操作提供了可靠的文件位置管理。

作者

我叫 Jan Bodnar,我是一名敬业的程序员,对编码充满热情。自 2007 年以来,我通过 1,400 多篇文章和 8 本电子书分享了我的专业知识。凭借十多年的教学经验,我致力于使编程变得易于访问且引人入胜。

列表 C 标准库