C 语言 fopen 与 fclose
更新时间:2026-08-26。本文是
languages/c/主题入门层第 60 篇。程序读配置、写日志、存数据,第一步都是打开文件。C 标准库用fopen拿到一个FILE*,用fclose归还。看起来简单,但模式串写错、忘判空、忘关闭——每个都是能让你调试到怀疑人生的坑。
本文要回答的问题
fopen的各种模式(r/w/a/+/b)分别什么意思?- 为什么必须判空?
fclose忘写了会怎样?
一、fopen 的完整签名
c
#include <stdio.h>
FILE *fp = fopen("data.txt", "r");- 第一个参数:文件路径(字符串);
- 第二个参数:模式串(见下表);
- 返回值:
FILE *成功;失败返回NULL。
二、模式串全家桶
| 模式 | 含义 | 文件不存在时 | 打开时清空原内容? |
|---|---|---|---|
"r" | 只读 | 失败 | — |
"w" | 只写(覆盖) | 创建 | ✅ 清空 |
"a" | 追加写 | 创建 | ❌ 保留,从尾部写 |
"r+" | 读写 | 失败 | ❌ |
"w+" | 读写(覆盖) | 创建 | ✅ 清空 |
"a+" | 读 + 追加写 | 创建 | ❌ |
"rb" / "wb" / "ab" | 二进制模式(Windows 上换行处理不同) | 同左 | 同左 |
三条重点:
"w"会清空文件——想"保留原内容追加"必须用"a",误用"w"就是数据清空事故;"r"读不存在的文件返回 NULL,必须先判空;- Windows 上读写文本文件建议加
b("rb"),否则\n会被转成\r\n,二进制文件会读错。
三、判空:打开文件可能失败
c
FILE *fp = fopen("config.ini", "r");
if (fp == NULL) {
perror("fopen"); // 打印具体原因:No such file / Permission denied
return 1;
}perror 会输出带 errno 描述的错误信息,比干巴巴的 NULL 有用得多。完整错误处理见文件错误处理。
四、fclose:用完必须还
c
fclose(fp); // 关闭文件,刷新缓冲区忘 fclose 的后果:
| 后果 | 说明 |
|---|---|
| 缓冲数据丢失 | 写的数据还在缓冲区没落盘 |
| 文件句柄泄漏 | 进程打开文件数有上限(ulimit -n) |
| 锁/独占问题 | Windows 上文件可能被锁住 |
fclose 时数据才真正落盘——写模式更要记得关。程序异常退出(exit/return from main)时库会清理,但显式 fclose 是好习惯。
五、路径与当前工作目录
fopen("data.txt", "r") 的相对路径是相对进程的当前工作目录(cwd),不是可执行文件所在目录:
bash
./app # 从当前目录运行,data.txt 找当前目录调试时"文件明明在同目录却打不开"?先 pwd 看运行目录。绝对路径最省心但代码不易移植;工程里常用相对路径 + 运行时确认 cwd。
六、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
想追加用了 "w" | 原文件被清空 | 追加用 "a" |
| 忘判空 | 空指针崩溃 | fopen 后立即判空 + perror |
| 忘 fclose | 数据丢失/句柄泄漏 | 用完即关 |
| 相对路径理解错 | 找不到文件 | 先 pwd 确认 cwd |
| Windows 二进制没加 b | 数据被 \r\n 污染 | 二进制用 "rb"/"wb" |
七、与本站主线衔接
- 打开之后怎么读怎么写,见字符与行读取、写入文件;
- 错误详情(errno/perror),见文件错误处理;
- 文件 IO 的缓冲区机制(stdio 缓冲),见stdio 缓冲原理。
一句话总结
fopen(路径, 模式) 返回 FILE*,失败返回 NULL 必须判空;模式串是命门——"w" 清空、"a" 追加、"r" 只读、加 b 才是二进制;用完 fclose 让数据落盘并释放句柄——打开是"签合同",模式是"合同条款",判空和关闭是"验收与退租"。