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
相关产品推荐
相关产品推荐

