二进制读写
1. 文本文件与二进制文件的区别
文本文件和二进制文件在存储格式、读写方式和适用场景上存在本质区别:
存储格式不同:
- 文本文件:只能存储文本数据(ASCII或Unicode字符),每个字符对应一个字节或多个字节
- 二进制文件:可以存储任何类型的数据,包括整数、浮点数、结构体、图像、音频等原始数据
读写方式不同:
- 文本文件使用格式化I/O函数(如
fprintf、fscanf) - 二进制文件使用原始I/O函数(如
fread、fwrite)
换行符处理不同:
- 文本文件在不同操作系统中的换行符会自动转换(Windows:
\r\n,Linux:\n) - 二进制文件不进行任何转换,按原样读写
2. 二进制读写函数详解
2.1 fwrite函数
c
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
参数说明:
ptr:指向要写入数据的指针size:每个数据项的大小(字节)n:要写入的数据项数量fp:文件指针
返回值: 成功写入的数据项数量
2.2 fread函数
c
size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
参数说明:
ptr:指向存储读取数据的缓冲区指针size:每个数据项的大小(字节)n:要读取的数据项数量fp:文件指针
返回值: 成功读取的数据项数量
3. 实践示例
示例1:写入和读取整数数组
c
#include <stdio.h>
int main() {
// 写入二进制数据
int numbers[] = {10, 20, 30, 40, 50};
FILE *fp = fopen("data.bin", "wb");
if (fp == NULL) {
printf("文件打开失败!\n");
return 1;
}
// 写入整个数组
size_t written = fwrite(numbers, sizeof(int), 5, fp);
printf("成功写入 %zu 个整数\n", written);
fclose(fp);
// 读取二进制数据
int read_numbers[5];
fp = fopen("data.bin", "rb");
if (fp == NULL) {
printf("文件打开失败!\n");
return 1;
}
size_t read = fread(read_numbers, sizeof(int), 5, fp);
printf("成功读取 %zu 个整数:", read);
for (int i = 0; i < read; i++) {
printf("%d ", read_numbers[i]);
}
printf("\n");
fclose(fp);
return 0;
}
示例2:写入和读取结构体
c
#include <stdio.h>
#include <string.h>
typedef struct {
int id;
char name[20];
float score;
} Student;
int main() {
Student stu1 = {1001, "张三", 85.5};
Student stu2 = {1002, "李四", 92.0};
// 写入结构体
FILE *fp = fopen("students.bin", "wb");
if (fp) {
fwrite(&stu1, sizeof(Student), 1, fp);
fwrite(&stu2, sizeof(Student), 1, fp);
fclose(fp);
}
// 读取结构体
Student stu_read;
fp = fopen("students.bin", "rb");
if (fp) {
printf("学生信息:\n");
while (fread(&stu_read, sizeof(Student), 1, fp) == 1) {
printf("ID: %d, 姓名: %s, 分数: %.1f\n",
stu_read.id, stu_read.name, stu_read.score);
}
fclose(fp);
}
return 0;
}
4. 二进制文件操作的最佳实践
- 检查返回值 :始终检查
fread和fwrite的返回值,确保读写操作成功 - 使用正确的打开模式 :
"rb":以二进制只读方式打开"wb":以二进制只写方式打开(会清空文件)"ab":以二进制追加方式打开"rb+":以二进制读写方式打开
- 处理文件大小 :使用
fseek和ftell获取文件大小,避免读取超出文件范围 - 内存对齐 :结构体成员可能需要内存对齐,使用
#pragma pack或编译器选项控制
5. 性能对比
| 操作类型 | 文本文件 | 二进制文件 |
|---|---|---|
| 写入速度 | 较慢(需要格式化) | 较快(直接内存拷贝) |
| 读取速度 | 较慢(需要解析) | 较快(直接加载到内存) |
| 文件大小 | 较大 | 较小 |
| 可读性 | 高 | 低 |
| 跨平台 | 需要处理换行符 | 需要处理字节序 |