函数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
注意:
- 进程关闭一个文件会释放它加在该文件上的所有记录锁。
- 当一个进程终止时,内核会自动关闭它所有的打开的文件。