fread 是 C 语言标准库 stdio.h 里面的二进制读取函数,作用是从已经打开的文件流当中,一次性读取指定数量的数据块,把读到的数据存入内存缓冲区,它和文本读取函数不一样,fread 是按二进制原始字节读取,不会对换行符 文本编码做自动转换,适合读取结构体 数组 图片 二进制文件这类非纯文本数据,做文件批量读取的时候效率比逐字符读取更高。之所以很多初学者会混淆 fread 和 fgets fgetc,是因为后两者专门面向文本读取,而 fread 定位就是二进制块读取,函数会返回成功读取到的数据块个数,这个返回值是判断读取是否完整的关键,很多 bug 就是没有判断返回值,默认读取一定成功,最后出现数据不完整。
函数原型
size_t fread (void ptr, size_t size, size_t nmemb, FILE stream)
参数逐项解释
1 ptr 内存缓冲区指针,读取出来的数据会保存到这块内存
2 size 单个数据块的字节大小
3 nmemb 想要读取的数据块数量
4 stream 已经通过 fopen 打开的文件指针
返回值 类型 size_t,代表实际成功读取的数据块数目,如果返回值小于 nmemb,一般代表读到文件末尾,或者读取过程发生错误
核心要点说明
读取逻辑
fread 总读取字节数等于 size 乘以 nmemb,比如 size 是 4,nmemb 是 10,总共尝试读取 40 字节。这里要重点理解,返回值是块数量,不是总字节数,很多新手误以为返回值是字节总数,这是高频错误。
打开模式要求
使用 fread 读取文件,fopen 打开文件的时候,推荐加上 rb 二进制只读模式,也就是 fopen (filename, "rb"),如果只用 r 文本模式,在 Windows 系统下会自动转换换行符,破坏二进制原始数据,读取二进制文件一定要用 rb。
基础示例步骤
1 引入头文件 stdio.h
2 定义缓冲区,比如字符数组或者结构体数组
3 调用 fopen 以 rb 模式打开文件,判断文件指针是否为空
4 调用 fread,传入缓冲区 单块大小 块数量 文件指针
5 判断 fread 返回值,确认读取块数
6 读取完成调用 fclose 关闭文件流
示例代码逻辑
char buf [100];
FILE fp = fopen ("test.bin", "rb");
if (fp != NULL)
{
int ret = fread (buf, 1, 100, fp);
fclose (fp);
}
这里 size 写 1,nmemb 写 100,ret 返回值就是读取到的字节数量,这种写法非常常用。
读取结构体场景
fread 非常适合直接读取结构体二进制数据,把结构体作为一块数据读取,size 填写 sizeof (结构体类型),nmemb 填写结构体个数,但是这种方式有坑,结构体存在内存对齐,跨平台或者编译器不同的时候,结构体布局可能不一样,二进制文件就会读取错乱。
常见异常情况
| 情况 | 现象 |
|---|---|
| 到达文件末尾 | fread 返回值小于请求的 nmemb |
| 文件流出错 | ferror 函数可以检测读取错误 |
| 文件未打开成功 | fp 为 NULL,不能调用 fread |
| 打开模式错误 | Windows 下文本模式读取二进制数据乱码 |
【常见问题】
问题 1 fread 函数的返回值是总字节数吗
回答 1 fread 函数的返回值不是总字节数,fread 函数返回的是成功读取的数据块数量,总字节数需要用返回值乘以 size 参数,学习 fread 函数的用法的时候一定要区分这个关键点。
问题 2 fread 函数读取文本文件可以吗
回答 1 fread 函数可以读取文本文件,但是 fread 函数本身是二进制读取,不会处理文本换行转换,如果是纯文本读取一般优先 fgets,使用 fread 函数读取文本文件建议依然用 rb 模式避免 Windows 换行转换问题。
问题 3 fread 函数和 fwrite 函数是什么搭配关系
回答 1 fwrite 是二进制写入函数,fread 函数一般和 fwrite 成对配套使用,先用 fwrite 写入二进制文件,再用 fread 函数读取回来,这是 C 语言二进制文件读写最经典组合。
问题 4 fread 函数读取到一半返回值变小是什么原因
回答 1 fread 函数读取中途返回值变小,大概率是已经抵达文件末尾,请求读取的数据块超出文件剩余内容,也有可能是文件流发生错误,使用 fread 函数的时候需要调用 feof 和 ferror 区分是读完文件还是出错。
【免责申明】
本教程基于标准 C 语言库 fread 函数编写,不同编译器 操作系统对文件流行为存在细微差异,二进制文件读写涉及内存对齐 字节序等跨平台问题,本内容仅作为编程学习参考,不承担代码运行异常 数据损坏等相关损失。


