2、文件的打开与关闭:fopen函数详解、fclose函数详解、文件打开模式
文件操作,说白了就是跟磁盘上的数据打交道。你写程序,数据不能总在内存里待着,一断电就没了。所以得学会怎么打开文件、读写文件、最后关掉它。今天咱们就先把「开门」和「关门」这两件事聊透。
2.1 fopen 函数详解
fopen 是 C 标准库里的一个函数,原型在 <stdio.h> 里。它的作用就是打开一个文件,返回一个文件指针。如果打开失败,返回 NULL。
FILE *fopen(const char *filename, const char *mode);
第一个参数是文件名,可以是相对路径或绝对路径。第二个参数是打开模式,决定了你能对文件做什么操作。
我个人习惯,每次打开文件后都会检查返回值。为什么?因为我在项目里吃过亏。有一次写日志模块,磁盘满了,fopen 返回 NULL,我没检查,后面直接往 NULL 指针里写数据,程序直接崩了。从那以后,我写 fopen 必跟一句:
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
perror("文件打开失败");
return -1;
}
嗯,这步不能省。
2.2 文件打开模式(r/w/a/r+/w+/a+)
打开模式是 fopen 的核心。选错了模式,轻则读不到数据,重则把文件内容清空了。咱们一个一个说。
| 模式 | 含义 | 文件不存在时 | 文件存在时 | 文件指针位置 |
|---|---|---|---|---|
"r" |
只读 | 返回 NULL | 正常打开 | 文件开头 |
"w" |
只写 | 创建新文件 | 清空内容 | 文件开头 |
"a" |
追加 | 创建新文件 | 保留内容 | 文件末尾 |
"r+" |
读写(不创建) | 返回 NULL | 正常打开 | 文件开头 |
"w+" |
读写(创建/清空) | 创建新文件 | 清空内容 | 文件开头 |
"a+" |
读写(追加) | 创建新文件 | 保留内容 | 文件末尾 |
重点提醒:
"w"和"w+"会清空文件内容。如果你只是想修改文件里的某几行,千万别用"w",否则数据就没了。"a"和"a+"只能往文件末尾写,不能往前插。你想想看,日志文件是不是都这样?"r+"可以读也可以写,但不会创建文件。如果你要打开一个配置文件,用"r+"比较安全。
我曾经在项目里犯过一个低级错误:用 "w" 模式打开一个用户数据文件,结果程序一跑,文件被清空了。还好有备份,不然就出大事了。所以我现在写代码,只要不是明确要新建文件,一律用 "r" 或 "r+"。
2.3 fclose 函数详解
文件用完了,得关掉。fclose 就是干这个的。
int fclose(FILE *stream);
它接受一个文件指针,关闭成功返回 0,失败返回 EOF。为什么一定要关?原因有三:
- 释放系统资源:每个打开的文件都会占用一个文件描述符。系统资源是有限的,不关的话,开多了就报 "Too many open files"。
- 刷新缓冲区:fwrite 写数据时,不一定立刻写到磁盘,可能还在缓冲区里。fclose 会强制把缓冲区里的数据刷到磁盘。
- 防止数据丢失:程序异常退出时,没关闭的文件可能导致数据没写完。fclose 能保证数据完整性。
小技巧:
我习惯在 fopen 之后,紧接着写 fclose 的代码。比如:
FILE *fp = fopen("test.txt", "r");
if (fp == NULL) {
// 错误处理
}
// ... 读写操作 ...
fclose(fp);
这样就不会忘记关了。你想想看,是不是比写到后面再回头补要靠谱?
注意:
fclose 之后,文件指针就失效了。不要再对 fp 做任何操作。如果你还想用,得重新 fopen。
2.4 知识体系图
下面这张图把文件打开与关闭的核心逻辑串起来了。你可以看到,fopen 是入口,fclose 是出口,中间是各种操作模式的选择。
这张图里,fopen 是起点,fclose 是终点。中间那个菱形判断,就是检查文件是否打开成功。我建议你把这个流程刻在脑子里,写文件操作代码时,每一步都按这个来。
2.5 完整示例
最后,给你一个完整的例子。它演示了如何用 "w+" 模式创建文件、写入数据、然后关闭。
#include <stdio.h>
int main() {
FILE *fp = fopen("example.txt", "w+");
if (fp == NULL) {
perror("无法打开文件");
return 1;
}
fprintf(fp, "Hello, 文件操作!\n");
fprintf(fp, "这是第二行。\n");
fclose(fp);
printf("文件写入完成。\n");
return 0;
}
运行之后,你会得到一个 example.txt 文件,里面有两行文字。如果你用 "r" 模式打开一个不存在的文件,fopen 会返回 NULL,程序就会打印错误信息。试试看?
个人经验:
我在做嵌入式项目时,经常需要读写配置文件。那时候我习惯用 "r" 模式先读,如果文件不存在,再用 "w" 创建默认配置。这样既不会误删已有文件,又能处理首次运行的情况。