C语言fread函数详解:“工厂传送带”
一句话理解 fread
「fread 就像工厂的传送带,从文件仓库中批量搬运二进制‘货物’到内存卡车,高效且精准!」
函数原型
#include
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
入口参数
参数 | 类型 | 比喻解释 |
ptr | void* | 内存中的「卡车」(存储数据的缓冲区) |
size | size_t | 每个「货物单元」的大小(字节) |
count | size_t | 希望搬运的货物单元数量 |
stream | FILE* | 数据来源的「仓库门」(文件指针) |
返回参数
返回值 | 含义 |
size_t | 实际成功搬运的货物单元数量(≤count) |
0 | 仓库已空或传送故障 |
核心功能图解
文件内容:■■■■■■■■■■■■■■■■■■■■(20字节)
fread(buffer, 5, 3, file) → 搬运15字节,返回3(成功搬运3个5字节单元)
代码实例:货物搬运实战
场景1:读取结构体数组(学生档案)
#include
typedef struct {
char name[20];
int age;
float score;
} Student;
int main() {
FILE *file = fopen("students.dat", "rb"); // 二进制读模式
if (!file) {
perror(" 档案库门打不开");
return 1;
}
Student classroom[3]; // 准备3个学生的“卡车”
size_t loaded = fread(classroom, sizeof(Student), 3, file);
if (loaded < 3) {
printf(" 只加载了%zu名学生数据\n", loaded);
if (feof(file)) printf("(档案已读完)\n");
if (ferror(file)) perror("(搬运故障)");
}
fclose(file);
return 0;
}
场景2:分块读取大文件(防止内存溢出)
#include
#define CHUNK_SIZE 4096 // 每次搬运4KB
int main() {
FILE *video = fopen("movie.mp4", "rb");
if (!video) return 1;
unsigned char buffer[CHUNK_SIZE]; // 4KB的“卡车”
size_t total_read = 0;
while (!feof(video)) {
size_t read = fread(buffer, 1, CHUNK_SIZE, video);
total_read += read;
// 处理本块数据(如加密/压缩/传输)
}
printf("总搬运量:%zu KB\n", total_read / 1024);
fclose(video);
return 0;
}
场景3:错误处理(检测文件完整性)
#include
int verify_file(const char *filename, size_t expected_size) {
FILE *file = fopen(filename, "rb");
if (!file) return -1;
char buffer[1024];
size_t total = 0;
while (!feof(file)) {
size_t read = fread(buffer, 1, sizeof(buffer), file);
total += read;
}
fclose(file);
return (total == expected_size) ? 0 : 1; // 验证文件大小
}
技术细节剖析
1. size 和 count 的黄金组合
- 乘法关系:总读取字节数 = size * count
- 灵活控制:
// 两种等效写法:
fread(buf, 1, 100, file); // 读100个1字节单元 → 100字节
fread(buf, 100, 1, file); // 读1个100字节单元 → 100字节
2. 返回值隐藏的密码
返回值 | 含义分析 |
=count | 完美搬运所有单元 |
<count | 文件剩余不足或读取错误 |
0 | 文件已结束或严重错误 |
常见错误与修复
1. 缓冲区溢出(卡车太小)
int data[10];
// 危险!文件可能包含超过40字节数据
fread(data, sizeof(int), 20, file); // 卡车容量仅40字节,却试图搬运80字节!
修复:
int data[20]; // 正确匹配容量
fread(data, sizeof(int), 20, file);
2. 忘记二进制模式(文本文件污染)
FILE *file = fopen("image.jpg", "r"); // 文本模式破坏二进制数据
fread(...);
修复:
FILE *file = fopen("image.jpg", "rb"); // 二进制模式
高级技巧:内存映射文件
// 结合fread实现高效数据处理(伪代码)
while (!feof(file)) {
fread(buffer, 1, CHUNK_SIZE, file);
process_data(buffer); // 加密/解密/分析
upload_to_network(buffer); // 分块传输
}
总结表格
特性 | 说明 |
核心功能 | 批量读取二进制数据 |
适用场景 | 结构体/数组存储、大文件处理 |
性能 | 适合块状读取,效率远超逐字节 |
安全准则 | 检查返回值,匹配缓冲区大小 |
总结
- 像智能传送带:fread 是C语言中处理二进制数据的核心工具,特点:
1 批量操作:高效搬运数据块,减少IO次数
2 精准控制:通过 size 和 count 精细调节读取粒度
3 跨平台兼容:统一处理文本/二进制文件(需正确设置模式) - 使用口诀:
「算好尺寸,检查货量;二进制门,必须打开;返回值验,错误不漏!」