3. 文件的打开与关闭:fopen与fclose详解

文件操作的第一步是什么?打开文件。最后一步呢?关闭文件。听起来简单,但我在项目中见过太多人在这两步上栽跟头。今天咱们就把这两个函数彻底讲透。

3.1 fopen函数——打开文件的钥匙

fopen的原型长这样:

FILE *fopen(const char *filename, const char *mode);

它返回一个FILE指针。如果打开失败,返回NULL。嗯,这个NULL检查特别重要,我后面会细说。

第一个参数是文件名,可以是相对路径或绝对路径。第二个参数是打开模式,这是重点中的重点。

3.2 文件打开模式——选对模式少踩坑

我整理了一张表,把六种常用模式列出来。你想想看,是不是经常搞混r+和w+的区别?

模式 含义 文件不存在 文件存在 文件指针位置
"r" 只读 返回NULL 正常打开 文件开头
"w" 只写 创建新文件 清空内容 文件开头
"a" 追加 创建新文件 保留内容 文件末尾
"r+" 读写(读为主) 返回NULL 正常打开 文件开头
"w+" 读写(写为主) 创建新文件 清空内容 文件开头
"a+" 读写(追加模式) 创建新文件 保留内容 文件末尾

我个人习惯把模式分成两组记忆:

  • 纯读写组:r、w、a。要么读要么写,不混用。
  • 读写混合组:r+、w+、a+。可以读也可以写,但行为差异很大。

⚠️ 特别注意:w和w+会清空文件!我在项目中遇到过有人用w+打开配置文件,结果文件内容全没了。如果你只是想修改文件内容,千万别用w+。

3.3 打开模式的实际应用场景

光看表格可能还不够直观。我结合项目经验说说每种模式什么时候用:

  • "r":读取配置文件、日志分析、数据导入。只读不写,最安全。
  • "w":生成新文件、覆盖旧数据。比如生成报表,每次运行都重新写一份。
  • "a":写日志文件。每次追加,不会丢失历史记录。
  • "r+":需要修改文件中的某些字段。比如更新数据库记录文件。
  • "w+":创建新文件并立即读写。我一般很少用,除非明确知道要清空。
  • "a+":既要追加又要读取。比如日志分析工具,先追加新日志,再读取分析。

💡 我的建议:能用"r"就别用"r+",能用"a"就别用"a+"。读写混合模式容易出bug,因为文件指针的位置需要你手动管理。

3.4 fclose函数——善始善终

打开文件后,一定要记得关闭。fclose的原型:

int fclose(FILE *stream);

成功返回0,失败返回EOF。为什么关闭文件这么重要?

  • 释放资源:每个打开的文件都会占用系统资源。嵌入式系统资源有限,不关闭会导致资源耗尽。
  • 刷新缓冲区:fclose会自动刷新缓冲区,确保数据真正写入磁盘。如果不关闭,数据可能还留在缓冲区里,程序崩溃就全丢了。
  • 避免文件损坏:多个程序同时操作同一个文件时,不关闭可能导致数据错乱。

🔑 核心原则:fopen和fclose必须成对出现。打开一个文件,就一定要关闭它。

3.5 标准实践——打开与关闭的完整流程

我写文件操作代码时,习惯用这个模板:

FILE *fp = NULL;

fp = fopen("data.txt", "r");
if (fp == NULL) {
    // 错误处理
    perror("打开文件失败");
    return -1;
}

// 文件操作...

if (fclose(fp) != 0) {
    perror("关闭文件失败");
    return -1;
}
fp = NULL;  // 避免野指针

为什么要检查fclose的返回值?我曾经在一个数据采集项目中,fclose返回了EOF,结果发现是磁盘空间满了。如果不检查,你根本不知道数据没写进去。

3.6 避坑指南——我踩过的那些坑

做嵌入式开发这么多年,文件操作这块我栽过不少跟头。分享几个典型问题:

  • 忘记检查fopen返回值:NULL指针直接操作,程序立马崩溃。现在我的代码里,fopen后面必跟NULL检查。
  • 用"w"打开配置文件:本来想修改,结果把文件清空了。后来我改成先用"r"打开,如果文件存在再用"r+"。
  • 忘记关闭文件:程序跑了一周,突然打不开文件了。一查,文件描述符泄漏了。从那以后,我写代码时fopen和fclose一定同时写出来。
  • 多线程操作同一个文件:两个线程同时写日志,内容混在一起。后来加了文件锁才解决。

⚠️ 嵌入式特别提醒:在单片机或RTOS环境下,文件系统可能不支持所有模式。比如有些轻量级文件系统不支持"a+"模式。用之前一定要查文档。

3.7 知识体系图

下面这张图把文件打开与关闭的核心逻辑串起来了:

文件打开与关闭核心流程 开始文件操作 fopen(filename, mode) 选择正确的打开模式 fp == NULL? 检查返回值 错误处理 执行文件读写操作 fclose(fp) 释放资源,刷新缓冲区

这张图展示了文件操作的标准流程:打开→检查→操作→关闭。每一步都不能少。

3.8 总结

文件打开与关闭看似基础,但细节决定成败。记住三点:

  • 选对模式,别让w+毁了你的数据
  • 检查返回值,NULL指针操作等于自杀
  • 成对出现,打开就一定要关闭

这些经验是我用实际项目中的bug换来的。你如果能把这三条刻在脑子里,文件操作这块基本不会出大问题。


公众号:蓝海资料掘金营,微信deep3321