ZetCode

C fsetpos 函数

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

文件定位在 C 编程中对于精确的文件操作至关重要。fsetpos 函数允许您将文件位置指示器设置到先前保存的位置。本教程将深入探讨 fsetpos,并结合实际示例解释其用法。您将学习如何将其与 fgetpos 结合使用以实现可靠的文件导航。掌握这些函数可以提高 C 程序中随机访问文件操作的效率。

什么是 fsetpos?

fsetpos 函数根据使用 fgetpos 之前获取的位置来设置流的文件位置指示器。它接受一个 FILE 指针和一个指向 fpos_t 对象的指针作为参数。此函数对于可能无法正确工作的 ftell 的大文件特别有用。始终检查返回值以处理错误。它在成功时返回零,在失败时返回非零。

fsetpos 的基本用法

此示例演示了 fsetpos 保存和恢复文件位置的基本用法。

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

此代码打开一个文件并使用 fgetpos 保存初始位置。读取一些数据后,它使用 fsetpos 恢复位置并再次读取相同的数据。fpos_t 类型存储位置信息。每一步都执行错误检查以确保正常运行。

跳转到特定位置

了解如何使用 fsetpos 跳转到文件中的不同位置。

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

此示例将三个不同的文件位置存储在一个 fpos_t 对象数组中。稍后,它使用 fsetpos 跳回到每个位置并从这些点读取数据。当您需要重新访问文件中的多个特定位置时,此技术非常有用。代码包含对每个位置设置操作的错误处理。

处理二进制文件

查看 fsetpos 如何与二进制文件配合使用以实现精确的数据访问。

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

此示例演示了 fsetpos 在二进制文件操作中的用法。它保存二进制文件中第二个记录的位置,对其进行修改,然后恢复位置以验证更改。fpos_t 变量可以与二进制文件无缝协作。这种方法非常适合数据库类操作,在这些操作中需要精确的记录访问。

fsetpos 的错误处理

妥善处理文件位置错误对于使用文件位置至关重要。此示例展示了健壮的错误检查。

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

此代码演示了对 fsetpos 及相关函数的全面错误处理。它会检查返回值并检查 errno 以获取特定的错误条件。该示例展示了如何处理无效的文件描述符和位置值。正确的错误处理可以使您的文件操作更加可靠且易于调试。

大文件支持

fsetpos 对于可能无法正确工作的 ftell 的大文件特别有用。

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

此示例展示了 fsetpos 如何处理非常大的文件中的位置。虽然 fpos_t 到数值的转换是平台特定的,但它演示了概念。为了获得真正可移植的代码,请使用 fgetposfsetpos,而无需解释 fpos_t 的内容。这种方法无论文件大小如何都能可靠工作。

与 fgetpos 结合使用

fsetpos 通常与 fgetpos 一起使用来保存和恢复位置。

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

此示例展示了 fgetposfsetpos 一起使用的实际用例。它标记起始位置,读取直到空行,然后标记该位置,之后处理两个位置之间的部分。这种模式对于处理文件段很有用。位置是使用它们内部的表示形式进行比较的。

文本模式与二进制模式的注意事项

了解文本模式和二进制模式如何影响 fsetpos 的行为。

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

此示例演示了在文本模式下获取的位置可能与二进制模式流不兼容,反之亦然。该代码以两种模式打开同一个文件,获取位置,并显示它们是不同的。尝试在文本模式流中使用二进制模式位置通常会失败。始终将位置与从中获取的流一起使用。

使用 fsetpos 的最佳实践

来源

C fsetpos 文档

本教程探讨了 C 语言中的 fsetpos 函数,演示了其在精确文件定位中的用法。从基本用法到处理大文件的复杂场景,这些示例为您的 C 程序中的文件处理提供了坚实的基础。

作者

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

列表 C 标准库