在 C 语言中,文件的读写是一个非常常见的需求。fopen 是标准库中提供的函数,用来打开文件,返回一个文件指针供后续操作使用。本篇博客将详细介绍 fopen 的使用方法、每个参数的含义,以及它与 Shell 中 >、>> 重定向符的联系与区别。
一、fopen 函数原型
FILE *fopen(const char *filename, const char *mode);
- filename:要打开的文件路径,可以是相对路径或绝对路径。
- mode:打开文件的方式,也叫“模式”,是一个字符串,控制你要如何访问文件(读、写、追加等)。
返回值是一个 FILE * 类型的文件指针,如果打开失败则返回 NULL。
二、mode 模式参数详解
模式 | 描述 | 文件是否需要存在? | 是否会清空原文件? |
---|---|---|---|
"r" | 只读模式打开文本文件 | 是 | 否 |
"w" | 只写模式打开文本文件 | 否 | 是(若存在则清空) |
"a" | 追加写入模式打开文本文件 | 否 | 否(写入时追加) |
"r+" | 读写模式打开文本文件 | 是 | 否 |
"w+" | 读写模式,若文件存在则清空 | 否 | 是 |
"a+" | 读写模式,从文件末尾追加写入 | 否 | 否 |
"rb" | 以二进制只读方式打开文件 | 是 | 否 |
"wb" | 以二进制只写方式打开文件 | 否 | 是 |
"ab" | 以二进制追加方式打开文件 | 否 | 否 |
2.1 “r”:只读模式
只能读取已有文件,文件必须存在。
#include <stdio.h>int main() {FILE *fp = fopen("data.txt", "r");if (!fp) {perror("无法打开文件");return 1;}char buffer[100];while (fgets(buffer, sizeof(buffer), fp)) {printf("%s", buffer);}fclose(fp);return 0;
}
在终端将显示data.txt中原有的文件内容
2.2 “w” 只写模式
fopen(“log.txt”, “w”) 以“写模式”(“w”)打开 log.txt 文件。如果文件不存在,它会被创建。如果文件已经存在,文件的原始内容会被清空,重新写入新内容。
fprintf(fp, “Hello, world!\n”); 这一行会将字符串 “Hello, world!\n” 写入 log.txt 文件中。
执行完后,文件会关闭,原文件中的所有内容(包括原先的 “hello”)都会被新内容覆盖。
假设log.txt中的内容为:
hello
那么执行下面的代码之后:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "w");if (!fp) {perror("无法打开文件");return 1;}fprintf(fp, "Hello, world!\n");fclose(fp);return 0;
}
因此,假设文件 log.txt 在之前包含 “hello”,再次运行此程序后,文件的内容会被重写为:
Hello, world!
2.3 “a”:追加模式
fopen(“log.txt”, “a”) 以“追加模式”(“a”)打开文件。如果 log.txt 文件不存在,它会被创建。如果文件已经存在,新写入的内容会被添加到文件的末尾,而不会覆盖原有的内容。
fprintf(fp, “程序执行了一次。\n”); 这一行会把字符串 “程序执行了一次。\n” 写入文件。
执行完后,文件会关闭。
假设文件 log.txt 中原本的内容为:
hello
那么执行下面的代码之后:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "a");if (!fp) {perror("无法打开文件");return 1;}fprintf(fp, "程序执行了一次。\n");fclose(fp);return 0;
}
每次执行该程序时,程序都会在文件末尾追加一行 “程序执行了一次。\n”,所以第一次执行后的文件内容会变为:
hello
程序执行了一次。
如果再次运行该程序,文件内容会变为:
hello
程序执行了一次。
程序执行了一次。
每次执行程序,都会在文件末尾追加 “程序执行了一次。\n” 这一行,而不会覆盖原有的内容。
2.4 “r+”:读写模式
fopen(“log.txt”, “r+”) 以“读写模式”(“r+”)打开文件。这种模式要求文件必须已经存在。如果文件不存在,程序会输出 无法打开文件 并退出。
fprintf(fp, “MODIFIED”); 会将字符串 “MODIFIED” 写入文件,从文件的开头开始覆盖原有的内容。由于 “MODIFIED” 的长度是 8 个字符,它会覆盖文件中的前 8 个字节。
假设原文件log.txt 的内容是:
hello
执行下面代码:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "r+");if (!fp) {perror("无法打开文件");return 1;}// 覆盖文件前几个字节fprintf(fp, "MODIFIED");fclose(fp);return 0;
}
执行 fprintf(fp, “MODIFIED”);,文件的前 8 个字节会被 “MODIFIED” 替换。由于 “MODIFIED” 比原来的 hello 长,因此文件会变成:
MODIFIED
2.5. “w+”:读写模式
fopen(“log.txt”, “w+”) 以“读写模式”(“w+”)打开文件。如果文件不存在,它会被创建。如果文件已经存在,它会被清空(即文件内容会被删除),然后可以进行读写操作。
fprintf(fp, “Writing then reading.\n”); 这一行将字符串 “Writing then reading.\n” 写入 log.txt 文件。
rewind(fp); 将文件指针移动回文件的开头,为后续的读取操作做准备。
fgets(buffer, sizeof(buffer), fp); 读取文件内容并将其存储在 buffer 数组中,直到遇到换行符或文件末尾。这里会读取写入的内容 “Writing then reading.\n”。
printf(“读取内容: %s”, buffer); 打印读取到的内容。
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "w+");if (!fp) {perror("无法打开文件");return 1;}fprintf(fp, "Writing then reading.\n");rewind(fp); // 返回文件开头char buffer[100];fgets(buffer, sizeof(buffer), fp);printf("读取内容: %s", buffer);fclose(fp);return 0;
}
控制台会输出:
读取内容: Writing then reading.
文件 log.txt 的内容会变为:
Writing then reading.
2.6 “a+”:读写追加模式
log.txt 文件的内容将被 追加 新数据,同时程序会读取并打印文件的全部内容。
fopen(“log.txt”, “a+”);
- 打开文件 log.txt,模式为 “a+”,表示 读写追加模式。
- 如果文件不存在,它会被创建;如果文件存在,原有内容 不会被清空,且新的写入内容会追加到文件末尾。
- 该模式允许读取和写入操作,但是写入内容总是从文件末尾开始,不会覆盖原有数据。
fprintf(fp, “添加一行数据\n”);
- 向文件追加一行数据 “添加一行数据\n”。由于是 “a+” 模式,文件指针会自动移到文件末尾,新的内容会添加到文件的末尾。
rewind(fp);
- 将文件指针重置到文件开头。这样做的目的是为了能够从文件的开始位置读取内容。
while (fgets(buffer, sizeof(buffer), fp))
- 使用 fgets 逐行读取文件内容,并将读取的每行内容打印出来。由于文件指针已被 rewind()
移动到文件开头,这个循环将从文件的第一行开始读取并输出。
假设文件 log.txt 原始内容是:
hello
执行下面代码后:
#include <stdio.h>int main() {FILE *fp = fopen("log.txt", "a+");if (!fp) {perror("无法打开文件");return 1;}fprintf(fp, "添加一行数据\n");rewind(fp); // 读取需要重置到文件开头char buffer[100];while (fgets(buffer, sizeof(buffer), fp)) {printf("%s", buffer);}fclose(fp);return 0;
}
文件内容变为:
hello
添加一行数据
程序会打印:
hello
添加一行数据
三、fopen 与 Shell 重定向 >、>> 的关系与区别
Shell 中的重定向:
1.>:输出重定向,若文件存在则清空,等价于 fopen(“file.txt”, “w”)。
2.>>:追加输出,文件存在时追加到末尾,等价于 fopen(“file.txt”, “a”)。
对比总结:
操作 | Shell 表达方式 | C 语言等价 fopen 模式 |
---|---|---|
重定向输出到文件(覆盖) | command > file.txt | "w" |
追加输出到文件 | command >> file.txt | "a" |
示例:
echo "日志内容" > log.txt # 覆盖写入
echo "更多日志" >> log.txt # 追加写入