一句话理解 fwrite
「fwrite 就像一位高效的二进制快递员,将内存中的‘货物’(数据块)批量打包,精准投递到文件仓库,支持任意数据类型!」
函数原型
#include
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
入口参数
参数 | 类型 | 比喻解释 |
ptr | const void* | 要投递的「货物地址」(数据指针) |
size | size_t | 每个「货物单元」的大小(字节) |
count | size_t | 希望投递的货物单元数量 |
stream | FILE* | 目标「仓库门」(文件指针) |
返回参数
返回值 | 含义 |
size_t | 实际成功投递的货物单元数量(≤count) |
0 | 投递失败(如磁盘满或文件未打开) |
核心功能图解
内存货物:■■■■■■■■■■(10字节)
fwrite(ptr, 2, 5, file) → 投递5个2字节单元(共10字节),返回5
代码实例:快递实战
场景1:保存结构体数组(学生数据存档)
#include
typedef struct {
char name[20];
int age;
float score;
} Student;
int main() {
Student class[3] = {
{"Alice", 20, 95.5},
{"Bob", 19, 88.0},
{"Charlie", 21, 76.5}
};
FILE *file = fopen("students.dat", "wb"); // 二进制写模式打开仓库门
if (!file) {
perror(" 仓库门打不开");
return 1;
}
// 投递3个学生数据单元
size_t shipped = fwrite(class, sizeof(Student), 3, file);
if (shipped < 3) {
printf(" 只投递了%zu份档案(磁盘可能已满)\n", shipped);
} else {
printf(" 学生档案已安全入库!\n");
}
fclose(file);
return 0;
}
场景2:分块写入大文件(视频备份)
#include
#define CHUNK_SIZE 4096 // 每次投递4KB
int main() {
FILE *source = fopen("input.mp4", "rb");
FILE *backup = fopen("backup.mp4", "wb");
if (!source || !backup) return 1;
unsigned char buffer[CHUNK_SIZE]; // 4KB的“快递箱”
size_t total_shipped = 0;
while (!feof(source)) {
// 从源文件读取一块数据
size_t read = fread(buffer, 1, CHUNK_SIZE, source);
// 投递到备份文件
size_t written = fwrite(buffer, 1, read, backup);
if (written < read) {
printf(" 第%zu块投递失败\n", total_shipped / CHUNK_SIZE);
break;
}
total_shipped += written;
}
printf("总投递量:%.2f MB\n", (double)total_shipped / (1024*1024));
fclose(source);
fclose(backup);
return 0;
}
场景3:错误处理(磁盘空间监控)
#include
int save_data(const char *filename, const void *data, size_t size) {
FILE *file = fopen(filename, "wb");
if (!file) return -1;
size_t written = fwrite(data, 1, size, file);
fclose(file);
if (written < size) {
printf(" 数据未完全写入(剩余%zu字节)\n", size - written);
return 1;
}
return 0;
}
int main() {
char big_data[1024*1024] = {0}; // 1MB数据
if (save_data("bigfile.bin", big_data, sizeof(big_data)) != 0) {
printf("请检查磁盘空间!\n");
}
return 0;
}
技术细节剖析
1. size 和 count 的黄金法则
- 乘法关系:总写入字节数 = size * count
- 灵活组合:
int arr[100];
fwrite(arr, sizeof(int), 100, file); // 写法1:100个int单元
fwrite(arr, 1, sizeof(arr), file); // 写法2:1个400字节单元(假设int为4字节)
2. 二进制模式的重要性
- 文本文件陷阱:在Windows中,文本模式会转换换行符(\n→\r\n),破坏二进制数据。
- 正确打开方式:
FILE *file = fopen("data.bin", "wb"); // 二进制模式
常见错误与修复
1. 缓冲区指针错误
int *data = malloc(10 * sizeof(int));
// 错误!指针未初始化或已释放
fwrite(data, sizeof(int), 10, file);
修复:
int data[10] = {0}; // 确保指针有效
fwrite(data, sizeof(int), 10, file);
2. 文件未以二进制模式打开
FILE *file = fopen("image.png", "w"); // 文本模式破坏数据
fwrite(pixels, 1, size, file);
修复:
FILE *file = fopen("image.png", "wb"); // 二进制模式
高级技巧:内存直接转储
#include
typedef struct {
int id;
double value;
char tag[4];
} SensorData;
void log_sensor(FILE *file, const SensorData *data) {
// 直接投递结构体(确保文件以二进制模式打开)
if (fwrite(data, sizeof(SensorData), 1, file) != 1) {
perror("传感器数据投递失败");
}
}
总结表格
特性 | 说明 |
核心功能 | 批量写入二进制数据 |
适用场景 | 结构体/数组存储、大文件备份 |
性能 | 高效,适合块状写入 |
安全准则 | 检查返回值,匹配缓冲区大小 |
总结
- 像专业快递员:fwrite 是C语言中处理二进制输出的核心工具,特点:
1 批量高效:减少IO操作,提升写入速度
2 精准控制:通过 size 和 count 调节写入粒度
3 跨平台可靠:二进制模式确保数据一致性 - 使用口诀:
「二进制门,必须打开;算好尺寸,验明货量;错误必查,安全送达!」