程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

C语言fread函数详解:“数据搬运工”

balukai 2025-03-26 09:42:05 文章精选 6 ℃

一句话理解 fread

「从文件的‘仓库’中批量搬运二进制‘货物’到内存‘卡车’中,按需装货,返回实际搬运的货物数量!」


函数原型

c

复制

#include   // 必须包含头文件
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

入口参数

参数

类型

比喻解释

ptr

void*

内存「卡车」的地址(存放数据)

size

size_t

每件「货物」的大小(单位:字节)

nmemb

size_t

希望搬运的货物件数

stream

FILE*

文件「仓库」的门(文件指针)

返回参数

返回值

含义

size_t

实际成功搬运的货物件数(≤ nmemb)


核心功能图解

假设文件内容(二进制):[A][A][B][B][C][C](每个字母占2字节)
调用 fread(ptr, 2, 3, file) → 搬运3件货物(每件2字节)
内存卡车内容:[A][A][B][B][C][C]
返回 3(成功搬运3件)

代码实例1:读取结构体数组

场景:读取学生成绩存档

#include 
#include 

// 定义「货物」结构
typedef struct {
    char name[20];
    int score;
} Student;

int main() {
    FILE *file = fopen("students.bin", "rb");  // 二进制读模式
    if (!file) {
        perror(" 仓库门打不开");
        return 1;
    }

    Student classroom[3];  // 准备3个学生的「卡车」

    // 从文件搬运数据:每件货物=1个Student,最多搬3件
    size_t loaded = fread(classroom, sizeof(Student), 3, file);

    if (loaded < 3) {
        printf(" 只搬运了%zu件货物,可能仓库没货了\n", loaded);
    } else {
        printf(" 成功搬运3名学生数据\n");
        for (int i = 0; i < 3; i++) {
            printf("学生%d: %s, 分数=%d\n", 
                   i+1, classroom[i].name, classroom[i].score);
        }
    }

    fclose(file);
    return 0;
}

代码实例2:读取图片文件头

场景:解析PNG文件特征

#include 

// PNG文件头特征(固定8字节)
#define PNG_HEADER_SIZE 8

int main() {
    FILE *image = fopen("photo.png", "rb");
    if (!image) {
        perror("图片仓库失联");
        return 1;
    }

    unsigned char header[PNG_HEADER_SIZE];  // 准备8字节的「小推车」

    // 搬运文件头:每件1字节,搬8件
    if (fread(header, 1, PNG_HEADER_SIZE, image) != PNG_HEADER_SIZE) {
        printf(" 文件头不完整\n");
        fclose(image);
        return 1;
    }

    // 检查PNG特征(89 50 4E 47 0D 0A 1A 0A)
    if (header[0] == 0x89 && header[1] == 0x50 && 
        header[2] == 0x4E && header[3] == 0x47) {
        printf(" 这是合法的PNG图片\n");
    } else {
        printf(" 文件头异常,疑似损坏\n");
    }

    fclose(image);
    return 0;
}

技术细节剖析

1.参数顺序的黄金法则

//  常见错误:size 和 nmemb 写反
fread(buffer, 100, 1, file);  // 搬运1件100字节的货物
fread(buffer, 1, 100, file);  // 搬运100件1字节的货物(效果相同,但语义不同)

2.返回值隐藏的密码

返回值

含义分析

= nmemb

完美搬运所有货物

< nmemb

可能遇到文件尾(EOF)或错误

0

仓库已空或发生错误

3.二进制模式的必要性

  • 在Windows系统中,必须用 "rb" 模式打开文件,否则会遇到换行符转换问题:
// 错误示范:文本模式读取二进制文件 FILE *file = fopen("data.bin", "r"); // 导致数据损坏

致命误区

1.缓冲区溢出

int arr[5];
// 危险!试图读取6个int,但卡车只能装5个
fread(arr, sizeof(int), 6, file);  // 内存越界!

2.类型不匹配

float data[10];
// 错误!文件存储的是double类型
fread(data, sizeof(double), 10, file);  // 数据解析错误

高级技巧:分块读取大文件

#define CHUNK_SIZE 4096  // 4KB的「卡车容量」
unsigned char buffer[CHUNK_SIZE];
size_t total_read = 0;

while (1) {
    size_t read = fread(buffer, 1, CHUNK_SIZE, file);
    total_read += read;
    if (read < CHUNK_SIZE) {
        if (feof(file)) {
            printf(" 全部货物搬运完成,总量:%zu字节\n", total_read);
        } else if (ferror(file)) {
            perror("搬运事故");
        }
        break;
    }
    // 处理本批次数据...
}

对比 fwrite

操作

方向

常见用途

fread

文件→内存

加载数据、反序列化

fwrite

内存→文件

保存数据、序列化


总结

  • 核心功能:批量读取二进制数据到内存
  • 必用场景:加载游戏存档、处理图像/音频、网络数据传输
  • 类比记忆:就像用叉车从仓库中成批搬运标准规格的集装箱到卡车上,fread 是C语言处理二进制数据的「物流专家」
最近发表
标签列表