在C语言开发中,处理二进制文件时,将文件内容读取到数组或缓冲区是高频需求,相比逐字节读取的方式,使用fread函数批量读取可以显著提升效率,减少系统调用次数。fread是标准库中专门用于二进制流读取的函数,能够快速将指定数量的二进制数据从文件复制到内存缓冲区中。
fread函数基本语法
fread的函数原型定义在stdio.h头文件中,具体语法如下:
#include <stdio.h> size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
各参数含义说明:
- ptr:指向存储读取数据的缓冲区数组的指针,也就是数据要存放的目标内存地址
- size:每个数据单元的字节大小,比如读取int类型数据则填sizeof(int)
- count:要读取的数据单元的数量
- stream:指向要读取的二进制文件的FILE指针
函数返回值是实际成功读取的数据单元数量,如果返回值小于count,可能是到达了文件末尾或者发生了读取错误。
批量读取到缓冲区的完整示例
以下是一个完整的示例,演示如何打开二进制文件,使用fread批量读取内容到字符数组缓冲区,并处理读取结果:
#include <stdio.h>
#include <stdlib.h>
int main() {
// 打开二进制文件,以只读方式打开
FILE *file = fopen("test.bin", "rb");
if (file == NULL) {
printf("文件打开失败n");
return 1;
}
// 定义缓冲区大小,这里设置为1024字节
#define BUFFER_SIZE 1024
unsigned char buffer[BUFFER_SIZE];
// 批量读取文件内容到缓冲区
size_t read_count = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, file);
if (read_count == 0) {
printf("未读取到数据或读取失败n");
} else {
printf("成功读取 %zu 个字节到缓冲区n", read_count);
// 这里可以对缓冲区中的数据进行处理,比如打印前10个字节的内容
printf("缓冲区前10个字节内容:");
for (size_t i = 0; i < read_count && i < 10; i++) {
printf("%02x ", buffer[i]);
}
printf("n");
}
// 关闭文件
fclose(file);
return 0;
}
读取技巧与注意事项
1. 合理设置缓冲区大小
缓冲区的大小需要根据实际场景调整,如果文件较小,可以直接将缓冲区大小设置为文件总大小,一次性读取全部内容。获取文件大小的方法如下:
#include <stdio.h>
long get_file_size(FILE *file) {
// 移动到文件末尾
fseek(file, 0, SEEK_END);
// 获取当前位置,即文件总字节数
long size = ftell(file);
// 将文件指针移回开头
fseek(file, 0, SEEK_SET);
return size;
}
获取到文件大小后,可以动态分配对应大小的缓冲区:
long file_size = get_file_size(file);
unsigned char *buffer = (unsigned char *)malloc(file_size * sizeof(unsigned char));
if (buffer == NULL) {
printf("内存分配失败n");
fclose(file);
return 1;
}
// 读取全部内容
size_t read_count = fread(buffer, 1, file_size, file);
2. 处理部分读取的情况
如果文件大小超过缓冲区的最大容量,需要循环调用fread读取剩余内容,直到文件末尾:
#define BUFFER_SIZE 1024
unsigned char buffer[BUFFER_SIZE];
size_t total_read = 0;
size_t read_count;
while ((read_count = fread(buffer, 1, BUFFER_SIZE, file)) > 0) {
total_read += read_count;
// 处理当前缓冲区中的数据
printf("本次读取 %zu 字节,累计读取 %zu 字节n", read_count, total_read);
}
3. 区分文件末尾和读取错误
当fread返回值小于count时,需要通过feof和ferror函数判断是到达文件末尾还是发生了错误:
size_t read_count = fread(buffer, 1, BUFFER_SIZE, file);
if (read_count < BUFFER_SIZE) {
if (feof(file)) {
printf("已到达文件末尾n");
}
if (ferror(file)) {
printf("读取过程中发生错误n");
}
}
常见问题解答
为什么打开文件要用rb模式
在Windows系统中,如果使用r模式打开二进制文件,系统会对换行符等特殊字符进行转换,导致读取到的内容和文件实际内容不一致,因此读取二进制文件时必须使用rb模式,避免字符转换。
fread和fscanf的区别是什么
fscanf是用于格式化读取文本文件的函数,会按照指定的格式解析内容,而fread是直接读取二进制数据,不会做任何格式转换,适合读取图片、音频、自定义二进制结构等文件。