UNIX环境高级编程 - 文件I/O - 打开/创建/关闭文件
函数open和openat
#include <fcntl.h>
int open(const char* path,int oflag,.../*mode_t mode*/);
int openat(int fd,const char*path,int oflag,.../*mode_t mode */);
可以使用如下命令查看参数:
man 2 open
-
参数:
-
path:要打开或者创建文件的名字 -
oflag:用于指定函数的操作行为:必选的标志:(标志/常量定义于
fcntl.h中)O_RDONLY常量:文件只读打开O_WRONLY常量:文件只写打开O_RDWR常量:文件读、写打开O_EXEC常量:只执行打开O_SEARCH常量:只搜索打开(应用于目录)。本文涉及的操作系统都没有支持该常
下面的常量是可选的(进行或运行)(不一定所有的操作系统支持,不同的系统得看实际情况):
O_APPEND:每次写时都追加到文件的尾端O_CLOEXEC:将FD_CLOEXEC常量设置为文件描述符标志O_CREAT:若此文件不存在则创建它。在使用此选项时,需要同时说明参数mode(指定该文件的访问权限)O_DIRECTORY:若path引用的不是目录,则出错O_EXCL:若同时指定了O_CREAT时,且文件已存在则出错。根据此可以测试一个文件是否存在。若不存在则创建此文件。这使得测试和创建两者成为一个原子操作O_NOCTTY:若path引用的是终端设备,则不将该设备分配作为此进程的控制终端O_NOFOLLOW:若path引用的是一个符号链接,则出错O_NONBLOCK:如果path引用的是一个FIFO、一个块特殊文件或者一个字符特殊文件,则文件本次打开操作和后续的 I/O 操作设为非阻塞模式。O_SYNC:每次write等待物理 I/O 完成,包括由write操作引起的文件属性更新所需的 I/OO_TRUNC: 如果此文件存在,且为O_WRONLY或者O_RDWR成功打开,则将其长度截断为0O_RSYNC:使每一个read操作等待,直到所有对文件同一部分挂起的写操作都完成。O_DSYNC:每次write等待物理 I/O 完成,但不包括由write操作引起的文件属性更新所需的 I/O
-
mode:文件访问权限。文件访问权限常量在<sys/stat.h>中定义,有以下九个:S_IRUSR:用户读S_IWUSR:用户写S_IXUSR:用户执行S_IRGRP:组读S_IWGRP:组写S_IXGRP:组执行S_IROTH:其他读S_IWOTH:其他写S_IXOTH:其他执行
-
-
返回值:
- 成功:返回文件描述符。
- 失败:返回 -1
由 open/openat 返回的文件描述符一定是最小的未使用的描述符数字。
对于openat函数,被打开的文件名由fd和path共同决定:
-
如果
path指定的是绝对路径,此时fd被忽略。openat等价于open -
如果
path指定的是相对路径名,则fd是一个打开目录的文件描述符。被打开的文件的绝对路径由该fd描述符对应的目录加上path组合而成 -
如果
path是一个相对路径名,而fd是特殊值AT_FDCWD,则path相对于当前工作目录。被打开文件在当前工作目录中查找。fd是AT_FDCWD说明是当前目录

openat 函数是 POSIX.1中新增的函数,希望解決两个问题。
-
让线程可以使用相对路径名打开目录中的文件,而不再只能打开当前工作目录。
- 同一进程中的所有线程共享相同的当前工作目录,因此很难让同一进程的多个不同线程在同时间工作在不同的目录中。
-
可以避免 time-of-check-to-time-of-use (TOCTTOU)错误。
- TOCTTOU 错误的基本思想是:如果有两个基于文件的函数调用,其中第二个调用依赖于第一个调用的结果,那么程序是脆弱的。
- 因为两个调用并不是原子操作,在两个函数调用之间文件可能改变了,这样也就造成了第一个调用的结果就不再有效,使得程序最终的结果是错误的。
函数creat
也可以使用creat 创建一个新文件。
#include <fcntl.h>
int creat(const char*path,mode_t mode);
此函数等效于:
open(path, O_WRONLY | O_CREAT | O_TRUNC, mode)
- 参数:
path:要创建文件的名字mode:指定该文件的访问权限文件访问权限常量在<sys/stat.h>中定义,有下列九个:S_IRUSR:用户读S_IWUSR:用户写S_IXUSR:用户执行S_IRGRP:组读S_IWGRP:组写S_IXGRP:组执行S_IROTH:其他读S_IWOTH:其他写S_IXOTH:其他执行
- 返回值:
- 成功: 返回
O_WRONLY打开的文件描述符 - 失败: 返回 -1
- 成功: 返回
creat的不足:
- 它以只写方式打开。若要先写再读,则需调用
creat、close,然后再调用open进行读取。 - 若文件已存在则将文件截断为0。
现在可以使用新的open:
open(path, O_RDWR | O_CREAT | O_TRUNC, mode)
为什么会有
open了还需要creat?历史原因,老版本的
open没有O_CREAT标志。
函数close
可以使用close 关闭一个打开文件。
#include <unistd.h>
int close(int fd);
- 参数:
fd:待关闭文件的文件描述符
- 返回值:
- 成功:返回 0
- 失败:返回 -1
注意:
- 进程关闭一个文件会释放它加在该文件上的所有记录锁。
- 当一个进程终止时,内核会自动关闭它所有的打开的文件。

浙公网安备 33010602011771号