1. C 库 API 的特点
在标准 C 语言库中有提供一套完整的文件操作 API,如 fopen()、fgets()、fread() 等,使用这些 API 可以对指定文件进行读写操作。
C 库 API 具备以下特征:
- 高兼容
有别于系统调用 API(如 Linux 下的 open()、read()、write() 等),C 库 API 是支持跨平台的。也就是说,无论在 Window、Linux 还是 Mac 系统环境下,C 库 API 都能够完美适配当前系统环境,不存在只能在特定系统条件下使用的问题。相对的,系统调用 API 如 read()、write() 等只能在 Unix/Linux 系统下使用。高兼容性是 C 库 API 的最大特点。
- 高性能
使用系统调用 API(如 Linux 下的 open()、read()、write() 等)为系统层级的直接调用,每次调用该类 API 时将发生系统上下文切换,系统开销较大。而 C 库 API 实际为系统调用 API 的上层封装,例如在 Linux 下 fread() 为 read() 的上层封装。C 库 API 在封装中使用了缓冲区来缓存输入输出,即多次调用 C 库 API 使缓冲区满后才将实际调用一次系统调用 API,这样能够减少上下文的切换次数,有效提升系统性能。缓冲区的大小缺省为一个宏定义
BUFSIZE
,具体数值在不同系统中可能不同,可使用 API 设置缓冲区的大小。
- 文件流
文件流为 C 语句中提出的概念。虽然文件分为许多类型,但文件的内容都是以二进制格式存储的。于是,C 语言对待文件时并不会区分具体的文件类型,而是都把文件看作为流,按字节处理。文件流的优点在于无具体的数据边界,完全由程序所控制。文件流的类型为
FILE
,其包含文件句柄、打开状态、缓冲区等信息。
- 局限性
在 Linux 系统中,虽有一切皆文件的说法,但使用 C 库的文件操作 API 也无法操作设备类型、管道类型等文件,只能操作普通类型的文本文件。需要对其他类型的文件时,需使用其对应的系统调用 API。
2. 常用文件操作 API
文件操作的 API 都在 C 标准库 <stdio.h> 中,在使用时只需包含该头文件即可。为了方便查阅,将使用索引来快速跳转到目标 API 介绍。索引列表如下:
- fopen():打开文件流
- fclose():关闭文件流
- feof():查询文件流对应的文件结束标识
- ferror():查询文件流对应的文件错误标识
- clearerr():清除文件流对应的文件标识
- fread():读文件流
- fwrite():写文件流
- fgets():读文件流
- fputs():写文件流
- fflush():刷新文件流
- fseek():更改文件流对应的文件指针所指位置
- ftell():获取文件流对应的文件指针所指位置
- fdopen():通过文件句柄打开对应的文件流
- fileno():通过文件流获取对应的文件句柄
- fgetpos():获取文件流对应的文件指针所指位置并保存下来
- fsetpos():设置文件流对应的文件指针所指位置
- setbuf():自定义文件流中缓冲区
- setvbuf():自定义文件流中缓冲区并指定缓冲模式
fopen()
- 函数声明
FILE* fopen (const char* filename, // 打来文件的名称
const char* mode // 文件打开方式
);
- 函数说明
以形参 mode
的方式打开文件 filename
。
mode
的基本选项如下:
mode | 描述 |
---|---|
“r” | 以可读方式打开文件,该文件必须存在。 |
“w” | 以可写方式打开文件,若存在同名文件则将清空覆盖,若无同名文件将创建新文件。 |
“a” | 以追加只写方式打开文件,若无同名文件将创建新文件。 |
“+” | 以读写模式打开文件,该文件必须存在。 |
“b” | 以二进制模式打开文件,该文件必须存在。 |
“t” | 以文本模式打开文件,为默认属性,该文件必须存在。 |
其中,"r"
、"w"
、"a"
为三种不同的打开方式,对应不同的操作权限,在使用时必须指定其中一个。如果同时指定多个方式时,以排在第一个的方式为准。"+"
、"b"
、"t"
为三种不同的打开模式。
在指定 mode
时,打开方式是必须的,打开模式是可选的,且必须打开方式在前打开模式在后。
打开成功时返回文件对应的文件流,失败时将返回 NULL。
- 使用示例
FILE* fp = fopen("test.txt", "r+");
if (fp == NULL)
{
printf("open test.txt failed !!\n");
}
fclose()
- 函数声明
int fclose (FILE* stream // 目标文件流
);
- 函数说明
刷新文件流,释放文件流相关资源,设置文件流的文件结束标识。
关闭成功时将返回 0,失败时将返回 EOF(-1)并设置文件错误标识。
- 使用示例
FILE* fp = fopen("test.txt", "r+");
if (fclose(fp) == EOF)
{
printf("close test.txt failed !!\n");
}
feof()
- 函数声明
int feof (FILE* stream // 目标文件流
);
- 函数说明
查询文件流对应的文件是否设置了文件结束标识,例如文件指针到达了文件末尾、使用 fclose() 关闭文件流的等情况。
已设置时将返回非 0,未设置时将返回 0。
- 使用示例
if (feof(fp) == 0)
{
// ...
}
ferror()
- 函数声明
int ferror (FILE* stream // 目标文件流
);
- 函数说明
查询文件流对应的文件是否设置了文件错误标识,例如关闭文件流失败、刷新文件流失败等情况。
已设置时将返回非 0,未设置时将返回 0。
- 使用示例
if (ferror(fp) == 0)
{
// ...
}
clearerr()
- 函数声明
int clearerr (FILE* stream // 目标文件流
);
- 函数说明
清除文件的结束标识和错误标识。
- 使用示例
clearerr(fp);
fwrite()
- 函数声明
size_t fwrite (const void* ptr, // 指向写入文件流的内容的内存
size_t size, // 写入元素大小,以字节为单位
size_t number