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

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.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:58:29