文件操作
FILE 类型及 FILE* 指针
FILE 类型的对象表示一个 C 语言的 I/O 流,其中包含关于这个流的信息。每个流与外部的物理设备(文件、标准输入流、打印机、序列端口等)相关联。
FILE* 是指向 FILE 对象的指针;通常把 FILE* 作为一个不透明指针 (Opaque pointer) 来使用,也就是说,不能直接访问它的成员,而是只能通过标准库函数进行操作。
具体实现未知
C 语言标准未指定 FILE 结构体的具体实现,甚至没有说明它是不是完整类型。FILE 对象可能在语义上不可复制。
补充:无论实现细节如何,从可移植编程的角度都应把 FILE 视为不透明实现细节,避免复制 FILE 对象(应通过 FILE* 与库函数来操作流)。
文件访问
在 C 语言中,文件操作主要通过 stdio.h 头文件中声明的函数来实现。最常用的文件操作函数包括:
打开文件
c
FILE* fopen(const char* filename, const char* mode);1
常用的模式有:
| 文件访问模式字符串 | 含义 | 解释 | 若文件已存在的动作 | 若文件不存在的动作 |
|---|---|---|---|---|
"r" | 读 | 打开文件以读取 | 从头读 | 打开失败 |
"w" | 写 | 创建文件以写入 | 销毁内容 | 创建新文件 |
"a" | 附加 | 附加到文件 | 写到结尾 | 创建新文件 |
字符串的其余部分可以包含以下任意顺序的字符,并进一步影响文件的打开方式:
"b":以二进制模式打开文件。"x":以独占模式打开文件。"p":以私有模式打开文件。"+":以更新模式打开文件(可读可写)。
标准提示
"b"在一些实现中对文本转换有影响;在另一些实现中可能没有区别,但当你希望按“字节序列”处理文件时,仍应使用二进制模式。"x"是标准的打开模式字符(C11 起引入)。"p"不是 C 标准定义的打开模式字符;如果你的实现支持,它属于扩展特性,应避免在可移植代码中依赖它。
关闭文件
c
int fclose(FILE* stream);1
直接输入输出
字符操作
c
int fputc(int c, FILE* stream); // 写入单个字符
int fgetc(FILE* stream); // 读取单个字符1
2
2
TIP
函数原型中的形参名只是说明用途;这里使用 c 以避免与关键字冲突。
字符串操作
c
int fputs(const char* str, FILE* stream); // 写入字符串
char* fgets(char* str, int n, FILE* stream); // 读取字符串1
2
2
格式化输入输出
c
int fprintf(FILE* stream, const char* format, ...); // 格式化写入
int fscanf(FILE* stream, const char* format, ...); // 格式化读取1
2
2
TIP
关于无格式/有格式输入输出的细节与常见坑,见 14.3。
文件定位
获取当前位置
c
long ftell(FILE* stream);1
设置位置
c
int fseek(FILE* stream, long offset, int whence);1
定位参数:
SEEK_SET: 文件开头SEEK_CUR: 当前位置SEEK_END: 文件末尾
重置位置
c
void rewind(FILE* stream); // 将位置重置到文件开头1
TIP
文本流定位存在限制,且更推荐使用 fgetpos / fsetpos(见 14.4)。
对文件的操作
文件重命名
c
int rename(const char* oldname, const char* newname);1
删除文件
c
int remove(const char* filename);1
示例代码
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
补充示例:把标准输入复制到文件
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
习题
#11421
⚡4⏳3
写一个程序:读入一个文件名 in 和一个文件名 out(都从标准输入读入),把 in 的内容复制到 out。
要求:
- 逐块读取与写入(不要逐字符);
- 检查每个 I/O 调用的返回值;
- 出错时要正确关闭已打开的文件。
#11422
⚡3⏳2
写一个程序:创建一个文件并写入若干行文本;然后把它重命名;最后删除它。
要求:对 rename / remove 的返回值进行检查。
本章内容对应 cppref 链接如下: