fwrite写入文件成功但fread无法读取数据的技术求助
解决fread无法读取fwrite写入的结构体数组问题
嘿,我来帮你排查下这个fread读不到数据的坑~你已经用fwrite成功写入了结构体数组,但读取失败,大概率是几个常见的二进制文件读写问题,我给你拆解下:
可能的原因&解决方案
1. 读取时用错了文件打开模式
你写入用的是"wb"(二进制写入模式),读取必须对应用"rb"(二进制读取模式)!如果用"r"文本模式,在Windows系统下会自动转换换行符(把0x0A换成0x0D0A),直接破坏结构体的二进制数据结构,导致读取出来的内容完全错乱。
2. 没检查fwrite/fread的返回值
很多人会忽略这一步,但这是排查问题的关键:
fwrite返回的是成功写入的元素个数(不是字节数),你要判断它是否等于numberofbooks,如果不等说明写入时就出错了(比如磁盘满了)。fread同理,返回的是成功读取的元素个数,如果不等于预期数量,要么是文件尾到了,要么是读取出错,你可以用feof()和ferror()来区分。
3. 结构体的内存对齐差异
不同编译器、不同平台对结构体的内存对齐规则可能不一样,比如有些编译器会给结构体成员补字节对齐,导致sizeof(struct NOVEL)在写入和读取时不一样,这会直接导致读取错位。解决方法是强制1字节对齐:
#pragma pack(1) // 开启强制1字节对齐 struct NOVEL { // 你的结构体成员 }; #pragma pack() // 恢复默认对齐
4. 文件指针位置不对
如果读取前文件指针不在文件开头(比如之前对这个文件做过其他操作),需要手动把指针移到开头:
fseek(fp, 0, SEEK_SET);
5. 结构体里有指针成员(如果有的话)
如果你的struct NOVEL里有指针(比如char* title),fwrite只会写入指针的内存地址,而不是指针指向的实际内容。读取时这个地址已经无效了,所以读出来的是垃圾数据。这种情况建议用固定长度的数组来存字符串(比如char title[100]),或者手动序列化/反序列化每个指针指向的内容。
完整示例代码
写入部分(修正版)
#include <stdio.h> #include <stdlib.h> // 强制对齐避免跨平台问题 #pragma pack(1) struct NOVEL { char title[50]; int pages; float rating; }; #pragma pack() int main() { const char* filename = "books.dat"; struct NOVEL books[2] = { {"The Hobbit", 310, 4.6}, {"Harry Potter", 332, 4.9} }; int numberofbooks = 2; FILE* fpnew = fopen(filename, "wb"); if (fpnew == NULL) { printf("Can't open the file name: %s", filename); exit(1); } // 检查写入是否成功 size_t written = fwrite(books, sizeof(struct NOVEL), numberofbooks, fpnew); if (written != numberofbooks) { printf("Warning: Only wrote %zu/%d books\n", written, numberofbooks); } // 务必正确关闭文件(你代码里的fpne...应该是笔误) fclose(fpnew); return 0; }
读取部分
#include <stdio.h> #include <stdlib.h> #pragma pack(1) struct NOVEL { char title[50]; int pages; float rating; }; #pragma pack() int main() { const char* filename = "books.dat"; int numberofbooks = 2; // 或者先从文件里读取这个数值,更灵活 struct NOVEL* books = malloc(sizeof(struct NOVEL) * numberofbooks); if (!books) { printf("Memory allocation failed\n"); exit(1); } FILE* fp = fopen(filename, "rb"); // 必须用rb模式! if (fp == NULL) { printf("Can't open the file name: %s", filename); free(books); exit(1); } // 确保指针在文件开头 fseek(fp, 0, SEEK_SET); // 读取并检查结果 size_t read_count = fread(books, sizeof(struct NOVEL), numberofbooks, fp); if (read_count != numberofbooks) { printf("Only read %zu/%d books\n", read_count, numberofbooks); if (feof(fp)) printf("Reached end of file\n"); if (ferror(fp)) printf("File read error\n"); } else { // 验证读取结果 for (int i = 0; i < numberofbooks; i++) { printf("Book %d:\n Title: %s\n Pages: %d\n Rating: %.1f\n", i+1, books[i].title, books[i].pages, books[i].rating); } } fclose(fp); free(books); return 0; }
额外优化建议
为了更健壮,建议把numberofbooks也写入文件开头,这样读取时不需要硬编码数量:
// 写入时先写数量 fwrite(&numberofbooks, sizeof(int), 1, fpnew); // 再写结构体数组 fwrite(books, sizeof(struct NOVEL), numberofbooks, fpnew); // 读取时先读数量 int read_num; fread(&read_num, sizeof(int), 1, fp); // 再分配内存读取数组 struct NOVEL* books = malloc(sizeof(struct NOVEL) * read_num);
内容的提问来源于stack exchange,提问作者Dylan N.
相关产品推荐
相关产品推荐

