C 编程/stdio.h/fopen
fopen,在 glibc 和 musl 中实现,将使用 open 系统调用。
使用 fopen
打开文件,它返回一个与指定文件或其他设备关联的 I/O 流,可以从中进行读写。如果函数失败,它将返回一个空指针。
相关的 C 库函数 freopen
在首先关闭与其参数关联的任何打开流后执行相同的操作。
它们被定义为
FILE *fopen(const char *path, const char *mode);
FILE *freopen(const char *path, const char *mode, FILE *fp);
fopen
函数本质上是 Unix 操作系统 open
系统调用的稍微高级一点的包装器。同样,fclose
通常是 Unix 系统调用 close
的一个薄包装器,而 C FILE
结构本身通常对应于一个 Unix 文件描述符。在 POSIX 环境中,fdopen
函数可用于从文件描述符初始化 FILE
结构;但是,文件描述符是一个纯粹的 Unix 概念,在标准 C 中不存在。
fopen
和 freopen
的 mode
参数必须是一个以以下序列之一开头的字符串
模式 | 描述 | 开始.. | ||
---|---|---|---|---|
r | rb | 以读模式打开(文件必须存在) | 开头 | |
w | wb | 以写模式打开(如果文件不存在则创建文件)。删除内容并覆盖文件。 | 开头 | |
a | ab | 以追加模式打开(如果文件不存在则创建文件) | 结尾 | |
r+ | rb+ | r+b | 以读写模式打开(文件必须存在) | 开头 |
w+ | wb+ | w+b | 以读写模式打开。如果文件存在,则删除内容并覆盖文件,否则创建一个空的新的文件 | 开头 |
a+ | ab+ | a+b | 以读写模式打开(如果文件存在则追加) | 结尾 |
“b” 代表二进制。C 标准提供了两种类型的文件——文本文件和二进制文件——尽管操作系统不需要区分两者。文本文件 是一个由文本组成的文件,这些文本按行排列,并带有某种区分行尾的字符或序列(在 Unix 中,一个裸行进字符;在 Microsoft Windows 中,一个回车符后跟一个换行符)。当从文本文件读取字节时,行尾序列通常映射到换行符以方便处理。当写入文本文件时,在写入之前,一个裸换行符被映射到 OS 特定的行尾字符序列。二进制文件 是一个文件,其中字节以“原始”方式读入,并以“原始”方式传送,没有任何映射。
当以更新模式打开文件时('+' 作为模式参数中的第二个或第三个字符),可以在关联的流上执行输入和输出。但是,写操作不能在没有对 fflush
或文件定位函数(fseek
、fsetpos
或 rewind
)的中间调用情况下紧随读操作之后,读操作也不能在没有对文件定位函数的中间调用情况下紧随写操作之后。[1]
写入和追加模式将尝试创建给定名称的文件,如果还没有这样的文件。如上所述,如果此操作失败,fopen
将返回 NULL
。
Musl 和 Glibc 在 Linux 上支持e模式,它在新的文件描述符上设置O_CLOEXEC。O_CLOEXEC是 Linux 2.6 的功能,在 Linux 手册页项目 中有记录
为新的文件描述符启用 close-on-exec 标志。指定此标志允许程序避免额外的 fcntl(2) F_SETFD 操作来设置 FD_CLOEXEC 标志。此外,在某些多线程程序中使用此标志至关重要,因为使用单独的 fcntl(2) F_SETFD 操作来设置 FD_CLOEXEC 标志不足以避免一个线程打开文件描述符时另一个线程执行 fork(2) 加 execve(2) 时的竞争条件。
参见 http://danwalsh.livejournal.com/53603.html
参见 musl cgit 以了解 Musl 的实现。