如何从二进制文件中读取结构体数组的成员变量并解决读取异常问题
问题根因
- 最核心的错误是
create函数中写入结构体数组的参数错误:fwrite(&list, sizeof(file), numFiles, binFile);这里的list本身就是传入的结构体数组的首地址,你额外加了取地址符&,实际写入的是指针变量的内存地址,而非结构体数组的真实内容,所以读取出来的所有字段全是错位的乱数据。 - 存在结构体对齐隐患:你写入时是批量写入整个结构体,读取时是拆分成员逐个读取,如果编译器对结构体做了内存对齐填充,读写的偏移量会不匹配,也会导致数据错位。
- 文件名
name字段没有强制补\0,就算读取正确也可能因为没有字符串结束符打印乱码。
修复代码
1. 修正create函数的fwrite参数
int create(char *archiveFile, file list[], int numFiles) { FILE *binFile; binFile = fopen(archiveFile, "wb"); if (binFile == NULL) { fprintf(stderr, "error opening file\n"); exit(1); } // 写入文件数量 fwrite(&numFiles, sizeof(numFiles), 1, binFile); // 修正:去掉list前的&,直接传数组首地址 fwrite(list, sizeof(file), numFiles, binFile); fclose(binFile); writeContentsToBin(archiveFile, list, numFiles); return 0; }
2. 修正list函数的读取逻辑,避免对齐问题,同时保证文件名结束符
int list(char *archiveFile) { FILE *binFile; int numFiles; file files[MAX]; binFile = fopen(archiveFile, "rb"); if (binFile == NULL) { fprintf(stderr, "binary file not opening\n"); exit(1); } // 获取当前文件数量,加返回值判断避免读空 if (fread(&numFiles, sizeof(numFiles), 1, binFile) != 1) { fprintf(stderr, "read file count failed\n"); fclose(binFile); exit(1); } // 修正:直接批量读取整个结构体数组,和写入逻辑对应,避免对齐问题 if (fread(files, sizeof(file), numFiles, binFile) != numFiles) { fprintf(stderr, "read file info failed\n"); fclose(binFile); exit(1); } // 打印内容,给name字段强制补结束符 for (int i = 0; i < numFiles; i++) { files[i].name[19] = '\0'; // name数组长度20,最后一位强制设为结束符 printf("name: %s\n", files[i].name); printf("size: %d\n", files[i].size); printf("offset: %d\n", files[i].offset); } fclose(binFile); return 0; }
额外优化建议
如果要彻底避免结构体对齐带来的跨编译器兼容性问题,可以给结构体定义加打包指令,比如GCC环境下可以写成:
typedef struct __attribute__((packed)) file { char name[20]; int size; int offset; } file;
该指令会要求编译器不给结构体加任何填充字节,内存布局完全和定义顺序一致。
内容的提问来源于stack exchange,提问作者Pochetes
相关产品推荐
相关产品推荐

