13.2 文件操作
1. FILE 类型及 FILE* 指针
FILE 类型的对象表示一个 C 语言的 I/O 流,其中包含关于这个流的信息。每个流与外部的物理设备(文件、标准输入流、打印机、序列端口等)相关联。
FILE* 是指向 FILE 对象的指针;通常把 FILE* 作为一个不透明指针 (Opaque pointer) 来使用,也就是说,不能直接访问它的成员,而是只能通过标准库函数进行操作。
具体实现未知
C 语言标准未指定 FILE 结构体的具体实现,甚至没有说明它是不是完整类型。FILE 对象可能在语义上不可复制。因此程序不应复制 FILE 对象,只通过 FILE* 和库函数操作流。
2. 文件访问
在 C 语言中,文件操作主要通过 stdio.h 头文件中声明的函数来实现。最常用的文件操作函数包括:
2.1 打开文件
c
FILE* fopen(const char* filename, const char* mode);1
常用的模式有:
| 文件访问模式字符串 | 含义 | 解释 | 若文件已存在的动作 | 若文件不存在的动作 |
|---|---|---|---|---|
"r" | 读 | 打开文件以读取 | 从头读 | 打开失败 |
"w" | 写 | 创建文件以写入 | 销毁内容 | 创建新文件 |
"a" | 附加 | 附加到文件 | 写到结尾 | 创建新文件 |
模式字符串的首字母之后还可以追加以下字符,进一步影响文件的打开方式:
"b":以二进制模式打开文件。"x":以独占模式打开文件,只能与"w"组合,并放在模式字符串末尾(如"wx"、"wbx")。"+":以更新模式打开文件(可读可写)。
标准提示
"b"在一些实现中对文本转换有影响;在另一些实现中可能没有区别,但当你希望按“字节序列”处理文件时,仍应使用二进制模式。"x"是标准的打开模式字符(C11 起引入)。
2.2 关闭文件
c
int fclose(FILE* stream);1
3. 直接输入输出
3.1 字符操作
c
int fputc(int c, FILE* stream); // 写入单个字符
int fgetc(FILE* stream); // 读取单个字符1
2
2
3.2 字符串操作
c
int fputs(const char* str, FILE* stream); // 写入字符串
char* fgets(char* str, int n, FILE* stream); // 读取字符串1
2
2
3.3 格式化输入输出
c
int fprintf(FILE* stream, const char* format, ...); // 格式化写入
int fscanf(FILE* stream, const char* format, ...); // 格式化读取1
2
2
TIP
关于无格式与格式化输入输出的细节和常见错误,见 13.3。
4. 文件定位
4.1 获取当前位置
c
long ftell(FILE* stream);1
4.2 设置位置
c
int fseek(FILE* stream, long offset, int whence);1
定位参数:
SEEK_SET: 文件开头SEEK_CUR: 当前位置SEEK_END: 文件末尾
4.3 重置位置
c
void rewind(FILE* stream); // 将位置重置到文件开头1
TIP
文本流定位存在限制,且更推荐使用 fgetpos / fsetpos(见 13.4)。
5. 对文件的操作
5.1 文件重命名
c
int rename(const char* oldname, const char* newname);1
5.2 删除文件
c
int remove(const char* filename);1
6. 示例代码
c
#include <stdio.h>
int main(void) {
FILE* fp;
char buffer[100];
// 写入文件
fp = fopen("test.txt", "w");
if (fp != NULL) {
fprintf(fp, "Hello, File!\n");
fclose(fp);
}
// 读取文件
fp = fopen("test.txt", "r");
if (fp != NULL) {
fgets(buffer, 100, fp);
printf("读取的内容:%s", buffer);
fclose(fp);
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
两次打开文件均成功时,标准输出为:
bash
读取的内容:Hello, File!
程序同时会在当前工作目录创建或覆盖 test.txt,其中保存一行 Hello, File!。
7. 补充示例:把标准输入复制到文件
c
#include <stdio.h>
int main(void) {
FILE* out = fopen("out.txt", "w");
if (out == NULL) {
return 1;
}
int ch;
while ((ch = getchar()) != EOF) {
if (fputc(ch, out) == EOF) {
fclose(out);
return 1;
}
}
if (fclose(out) == EOF) {
return 1;
}
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
8. 习题
#11304
⚡4⏳3
写一个程序:读入一个文件名 in 和一个文件名 out(都从标准输入读入),把 in 的内容复制到 out。
要求:
- 逐块读取与写入(不要逐字符);
- 检查每个 I/O 调用的返回值;
- 出错时要正确关闭已打开的文件。
#11305
⚡3⏳2
写一个程序:创建一个文件并写入若干行文本;然后把它重命名;最后删除它。
要求:对 rename / remove 的返回值进行检查。
本章内容对应 cppref 链接如下: