C 库函数 – fwrite()(建议收藏)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言:理解 fwrite() 的核心作用

在 C 语言编程中,文件操作是开发应用时绕不开的环节。无论是保存配置信息、处理二进制数据,还是构建复杂的日志系统,都离不开对文件的读写能力。而 fwrite() 函数作为 C 标准库中用于写入数据到文件的核心函数,其作用类似于快递员将包裹精准打包并发送到指定地址。它允许开发者以高效且灵活的方式,将内存中的数据批量传输到磁盘文件中。

本文将通过循序渐进的方式,从函数原型、参数解析、使用案例到常见问题,全面解析 fwrite() 的工作原理与实践技巧。无论是编程新手还是有一定经验的开发者,都能从中获得实用的知识与灵感。


函数原型与参数详解

函数原型

size_t fwrite( const void *ptr, size_t size, size_t count, FILE *stream );

fwrite() 的参数设计体现了 C 语言简洁高效的特点。它的五个参数(实际为四个,const void *ptr 是第一个)分别控制数据源、数据块大小、写入数量和目标文件流。

参数解析

参数名作用说明关键点
const void *ptr指向要写入数据的内存地址必须是常量指针,确保数据在写入过程中不被修改
size_t size每个数据项的字节大小例如,写入 int 类型时为 sizeof(int)
size_t count要写入的数据项数量总写入字节数为 size * count
FILE *stream文件指针,指向已打开的文件文件必须以写入模式(如 "wb""ab")打开

比喻理解
可以把 fwrite() 想象成一个智能打包机

  • ptr 是你放在传送带上的包裹(数据源),
  • size 是每个包裹的体积(字节大小),
  • count 是要打包的包裹数量,
  • stream 是快递员(文件流)负责将包裹送到指定地址(文件)。

使用步骤与代码示例

步骤 1:打开文件流

在调用 fwrite() 之前,必须先通过 fopen() 打开文件,并确保文件以写入模式(如 "wb")打开。

FILE *file = fopen("data.bin", "wb");  
if (file == NULL) {  
    perror("Failed to open file");  
    exit(EXIT_FAILURE);  
}  

步骤 2:准备数据与调用 fwrite()

假设我们要将一个 int 数组写入文件:

int numbers[] = {10, 20, 30, 40, 50};  
size_t num_count = fwrite(numbers, sizeof(int), 5, file);  

if (num_count != 5) {  
    fprintf(stderr, "Failed to write all elements\n");  
}  

关键点说明

  • sizeof(int) 定义了每个整数的字节大小(通常为 4 或 8 字节,取决于系统)。
  • 5 是要写入的元素数量。
  • 返回值 num_count 需要与预期值比较,以检测写入是否成功。

步骤 3:关闭文件流

完成写入后,务必调用 fclose() 释放资源:

fclose(file);  

进阶案例:保存结构体到文件

场景:存储学生信息

假设有一个结构体 Student

struct Student {  
    char name[50];  
    int age;  
    float gpa;  
};  

struct Student students[] = {  
    {"Alice", 20, 3.8},  
    {"Bob", 22, 3.5}  
};  

写入结构体到二进制文件

size_t num_items = sizeof(students) / sizeof(students[0]);  
size_t bytes_written = fwrite(students, sizeof(struct Student), num_items, file);  

if (bytes_written != num_items) {  
    // 处理错误  
}  

注意

  • 使用 sizeof(struct Student) 作为 size 参数,确保每个结构体的完整字节被写入。
  • 二进制文件的跨平台兼容性需谨慎处理(如字节序问题)。

常见问题与解决方案

问题 1:写入后文件为空或数据不完整

可能原因

  • 文件未以二进制模式打开(如误用 "w" 而非 "wb")。
  • 写入操作后未刷新缓冲区(fflush())或未关闭文件(fclose())。

解决方案

// 确保文件以二进制模式打开  
FILE *file = fopen("data.bin", "wb");  

// 强制刷新缓冲区(非必须,但可立即生效)  
fflush(file);  

// 最终关闭文件确保数据落地  
fclose(file);  

问题 2:写入二进制文件后无法读取

可能原因

  • 读取时未以二进制模式打开文件(如使用 "r")。
  • 读取时未按相同的数据类型和顺序解析。

修复示例

// 读取时同样使用二进制模式  
FILE *file = fopen("data.bin", "rb");  
struct Student read_student;  
fread(&read_student, sizeof(struct Student), 1, file);  

高级技巧与注意事项

技巧 1:动态内存与 fwrite()

对于动态分配的内存,fwrite() 依然适用:

int *dynamic_array = (int *)malloc(3 * sizeof(int));  
dynamic_array[0] = 100;  
dynamic_array[1] = 200;  
dynamic_array[2] = 300;  

fwrite(dynamic_array, sizeof(int), 3, file);  
free(dynamic_array); // 写入后可释放内存  

技巧 2:处理部分写入问题

fwrite() 返回值小于预期时,需判断是否因磁盘空间不足或文件流错误导致:

if (fwrite(buffer, size, count, file) < count) {  
    fprintf(stderr, "Write failed: %s\n", strerror(errno));  
}  

注意事项

  • 缓冲区问题:文件流默认启用缓冲,写入后可能未立即落盘。使用 fflush()fclose() 可强制写入。
  • 跨平台字节序:若数据需跨平台共享,需确保字节序一致(如使用 htonl() 等函数转换)。
  • 文本模式 vs 二进制模式:在 Windows 系统中,文本模式("w")会自动转换换行符,而二进制模式("wb")保持原始数据。

结论:掌握 fwrite() 的实践价值

fwrite() 是 C 语言中文件操作的基石,它以简洁的接口提供了强大的数据写入能力。通过本文的解析,读者应能理解其参数逻辑、掌握常见场景的实现方法,并规避潜在的错误风险。

无论是保存程序状态、传输二进制数据,还是构建持久化存储系统,fwrite() 都是开发者值得深入掌握的工具。建议读者通过实际项目练习,例如实现一个简单的文件加密工具或数据备份系统,以加深对函数特性的理解。

记住,编程如同搭建积木:基础函数是积木块,而你的创造力决定了最终作品的形态。继续探索,你的代码将能完成更复杂的任务!

最新发布