#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef unsigned int mode_t ;
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
函数功能
打开或创建一个文件
返回值
成功返回一个新的文件描述符(指代这个打开的文件),失败则返回 -1,并设置 errno 为相对应的错误标志
参数
pathname:路径名,标识要打开的文件(或目录)(例如:"./test.txt"、"/etc/passwd")
flags:位掩码,用于指定文件的打开模式。通过 O_RDONLY(只读)、O_WRONLY(只写) 或 O_RDWR(可读可写)中的其中一个打开文件的方式 与 下面的 0 个或多个可选模式按 位或(|) 操作得到。
flags | 说明 |
---|---|
O_CREAT | 若文件不存在将创建它。 |
O_EXCL | 这个标志需要和 O_CREAT 结合在一起使用,表明如果参数 pathname 标识的文件已经存在,则打开失败,此时 errno 会被设置为 EEXIST。 换言之,这个标志确保 open() 函数就是创建新文件的。 |
O_NOCTTY | 如果参数 pathname 引用的是终端设备,O_NOCTTY 标志表明不将该设备分配作为此进程的控制终端设备。如果 pathname 引用的不是终端设备,则此标志无效。 |
O_TRUNC | 如果文件已经存在且为普通文件,而且打开模块又是写(即是以 O_WRONLY 或 O_RDWR 模式打开的),那么将清空文件的原有的所有内容,并将其长度设置为 0。若文件是 FIFO 或终端设备文件,此标志会被忽略。 |
O_APPEND | 每次写文件都追加到文件的尾端。(不会覆盖原有的内容) |
O_NONBLOCK | 以非阻塞模式打开文件。 |
O_NDELAY | 以非阻塞模式打开文件,跟 O_NONBLOCK 是一样的,指向同一个标志位,推荐使用 O_NONBLOCK 标志,因为 O_NDELAY 是系统早期版本引入的,在读操作时,如果读不到数据,O_NDELAY会使 I/O 函数马上返回 0,但这又衍生出一个问题,因为读取到文件末尾(EOF)时返回的也是 0,这样无法区分是哪种情况。因此,O_NONBLOCK 就产生出来,它在读取不到数据时会回传 -1,并且设置 errno 为 EAGAIN。 |
O_SYNC | 以同步 I/O 方式打开文件,即每次 write 等待物理 I/O 操作完成,包括由该 write 操作引起的文件属性更新所需的 I/O 都操作完成。 |
O_LARGEFILE | 支持大文件模式打开文件,在 32 位操作系统中使用此标志,允许打开那些用 31 位都不能表示其长度的大文件。 |
O_DIRECTORY | 如果参数 pathname 不是目录,则打开失败,此时 errno 被设置为 ENOTDIR。 |
O_NOFOLLOW | 如果参数 pathname 引用的是一个符号链接,则 open() 函数打开失败,此时 errno 被设置为 ELOOP。 |
O_CLOEXEC | 将新打开的文件描述符设置 FD_CLOEXEC 标志,可以免去程序执行 fcntl() 函数时的 F_GETFD 和 F_SETFD 操作来设置 close-on-exec 标志的额外工作。 |
linux 内核中 <fcntl.h> 头文件对 O_NDELAY 的定义如下所示:
#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif
在 linux 内核中 <fcntl.h> 头文件对参数 flags 所有有效取值如下所示:
/* list of all valid flags for the open/openat flags argument: */
#define VALID_OPEN_FLAGS \
(O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | __O_SYNC | O_DSYNC | \
FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
mode:位掩码,用于当调用 open() 函数创建新文件时,指定文件的访问权限。如果参数 flags 中没有指定 O_CREAT 标志,则可以省略 mode 参数。
mode 参数所有有效取值如下:
mode | 说明 |
---|---|
S_ISUID | 执行时设置用户 ID |
S_ISGID | 执行时设置组 ID |
S_ISVTX | 粘着位,对目录使用 |
S_IRWXU | 用户可读,可写,可执行 |
S_IRUSR | 用户可读 |
S_IWUSR | 用户可写 |
S_IXUSR | 用户可执行 |
S_IRWXG | 组可读,可写,可执行 |
S_IRGRP | 组可读 |
S_IWGRP | 组可写 |
S_IXGRP | 组可执行 |
S_IRWXO | 其他用户可读,可写,可执行 |
S_IROTH | 其他用户可读 |
S_IWOTH | 其他用户可写 |
S_IXOTH | 其他用户可执行 |
S_IRWXUGO | 用户、同组用户以及其他用户都可读、可写、可执行 |
S_IRUGO | 用户、同组用户以及其他用户都可读 |
S_IWUGO | 用户、同组用户以及其他用户都可写 |
S_IXUGO | 用户、同组用户以及其他用户都可执行 |
S_IALLUGO | 以上列举的所有权限都有 |
在 linux 内核中 <sys/stat.h> 头文件对 mode 参数的有效取值定义如下所示:
#define S_ISUID 0004000
#define S_ISGID 0002000
#define S_ISVTX 0001000
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH)
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
例子
以下程序功能:打开 "./log.txt" 文件,并往该文件内容的末尾写一行 "hello world\n"
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int flags = O_WRONLY | O_CREAT | O_APPEND; /* 只读,没有该文件则创建,写时从文件内容的末尾附加新内容 */
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; /* rw-rw-rw- */
int fd = open("./log.txt", flags, mode);
if (fd < 0) {
perror("open error");
exit(EXIT_FAILURE);
}
char buf[] = "hello world\n";
ssize_t nwrite = write(fd, buf, strlen(buf));
if (nwrite < 0) {
perror("write error");
exit(EXIT_FAILURE);
}
printf("write success\n");
close(fd);
return 0;
}
参考:
《UNIX环境高级编程》(第3版)
《Linux-UNIX系统编程手册》