You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言读取二进制文件时无需feof仅通过fread判断文件结束终止循环的方法

实现方案

核心逻辑说明

fread 函数的返回值为实际成功读取的完整元素数量,当返回值小于你指定的待读取元素个数时,就代表已经到达文件末尾或发生读取错误,不需要额外调用feof即可判断终止条件。
你原有代码的问题在于,所有字段读取完成后才判断是否到文件尾,会导致最后一次读取到不完整的记录时,依然可能打印无效数据。

最优实现方案(直接读取完整结构体)

因为你的每条记录刚好对应一个完整的struct test结构体,直接一次性读取整个结构体即可,代码更简洁高效,修改后的完整代码如下:

#define MAX_CT 11
#include<stdio.h>
#include<stdlib.h>

// 如果写入二进制文件时用了无对齐的紧凑格式,可打开下面两行编译
// #pragma pack(1)
struct test
{
    short int a;
    double b;
    short int c;
    int d;
    float e;
    unsigned short f;
    unsigned char g;
    double h;
    unsigned long i;
    short int j;
    char k;
    int l;
    int m;
    int n;
    char o[MAX_CT];
    char p;
    double q;
};
// #pragma pack()

int main(int argc, char **argv)
{
    struct test a1;
    FILE *fp;

    // 输入参数校验
    if (argc < 2) {
        fprintf(stderr, "Usage: %s input_file\n", argv[0]);
        exit(1);
    }

    // 打开二进制文件
    fp = fopen(argv[1], "rb");
    if (fp == NULL){
        fprintf(stderr, "Cannot open the file %s\n", argv[1]);
        exit(1);
    }

    // 打印表头
    printf("a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q \n");

    // 核心循环:每次读取1个完整结构体,读取成功才执行打印逻辑
    while(fread(&a1, sizeof(a1), 1, fp) == 1) 
    {
        printf("%d, %f, %i, %d, %f, %u, %u, %f, %lu, %i, %i, %i, %i, %x, %s, %c, %f\n", 
            a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g, a1.h, a1.i, a1.j, 
            a1.k, a1.l, a1.m, a1.n, a1.o, a1.p, a1.q);
    }

    fclose(fp);
    return 0;
}

特殊场景:必须逐字段读取的实现

如果你有特殊需求必须逐个读取结构体字段,就要对每个fread的返回值做判断,只要任意一个字段读取返回值不等于1,就直接终止循环:

while(1) 
{
    // 每个字段读取都判断返回值,只要读取失败直接退出循环
    if (fread(&a1.a, sizeof(a1.a), 1, fp) != 1) break;
    if (fread(&a1.b, sizeof(a1.b), 1, fp) != 1) break;
    if (fread(&a1.c, sizeof(a1.c), 1, fp) != 1) break;
    if (fread(&a1.d, sizeof(a1.d), 1, fp) != 1) break;
    if (fread(&a1.e, sizeof(a1.e), 1, fp) != 1) break;
    if (fread(&a1.f, sizeof(a1.f), 1, fp) != 1) break;
    if (fread(&a1.g, sizeof(a1.g), 1, fp) != 1) break;
    if (fread(&a1.h, sizeof(a1.h), 1, fp) != 1) break;
    if (fread(&a1.i, sizeof(a1.i), 1, fp) != 1) break;
    if (fread(&a1.j, sizeof(a1.j), 1, fp) != 1) break;
    if (fread(&a1.k, sizeof(a1.k), 1, fp) != 1) break;
    if (fread(&a1.l, sizeof(a1.l), 1, fp) != 1) break;
    if (fread(&a1.m, sizeof(a1.m), 1, fp) != 1) break;
    if (fread(&a1.n, sizeof(a1.n), 1, fp) != 1) break;
    if (fread(&a1.o, sizeof(a1.o), 1, fp) != 1) break;
    if (fread(&a1.p, sizeof(a1.p), 1, fp) != 1) break;
    if (fread(&a1.q, sizeof(a1.q), 1, fp) != 1) break;

    // 所有字段读取成功才执行打印
    printf("%d, %f, %i, %d, %f, %u, %u, %f, %lu, %i, %i, %i, %i, %x, %s, %c, %f\n", 
        a1.a, a1.b, a1.c, a1.d, a1.e, a1.f, a1.g, a1.h, a1.i, a1.j, 
        a1.k, a1.l, a1.m, a1.n, a1.o, a1.p, a1.q);
}

注意事项

  • 确保二进制文件的写入逻辑和当前C程序的结构体内存对齐规则一致。如果文件是按无填充的紧凑字节顺序写入的,需要打开代码中注释的#pragma pack相关配置,关闭结构体自动对齐,避免字段偏移错误。
  • 打印字段时注意格式符匹配:比如unsigned char类型建议用%u打印,unsigned short建议用%u打印,char o[MAX_CT]要确保存储的字符串以\0结尾,否则使用%s打印会出现内存越界问题。

内容的提问来源于stack exchange,提问作者staypersistent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 02:12:03