File I/O open()函数
2019-08-01 本文已影响0人
无无吴
Opening Files
The Open() System Call
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open (const char *name, int flags);
int open (const char *name, int flags, mode_t mode);
Flags for open()
- O_RDONLY
- O_WRONLY
- O_RDWR
- O_APPEND
- O_ASYNC(当指定的文件变为可读或可写时,将生成信号(默认情况下为SIGIO)。此标志仅适用于FIFO、管道、套接字和终端,而不适用于常规文件。)
- O_CLOEXEC(在打开的文件上设置关闭的EXEC标志。执行新进程后,文件将自动关闭。这样就无需调用fcntl()来设置fand,从而消除了争用条件。此标志仅在Linux内核2.6及更高版本中可用。)
- O_CREAT(如果以名称表示的文件不存在,内核将创建它。如果文件已经存在,则除非给出O_EXCL,否则此标志无效。)
- O_DIRECT(该文件将被打开用于Direct I/O)
- O_DIRECTORY(如果name不是目录,则对open()的调用将失败。opendir()库调用在内部使用此标志。)
- O_EXCL(当使用O_CREAT时,如果名称给定的文件已经存在,则此标志将导致对open()的调用失败。这用于防止在创建文件时出现争用条件。如果O_CREAT没有提供, 这这个标志位没有任何意义。)
- O_LARGEFILE(给定的文件将使用64位偏移打开,允许对大于2G的文件进行操作。这是隐含在64位架构上的。)
- O_NOATIME+ (文件不会因为读而更新access time,防止一些重要的写行为被读而覆盖)
- O_NOCTTY(如果给定的名称引用终端设备(例如,/dev/TTY),它将不会成为进程的控制终端,即使该进程目前没有控制终端。这个标志位不常使用。)
- O_NOFOLLOW(如果文件名字是一个symbolic link, 那么调用open()会失败。通常,链接被解析,目标文件被打开。如果给定路径中的其他组件是链接,则调用仍将成功。例如,如果名称为/etc/ship/plank.txt,如果plank.txt是一个symbolic link,则失败。然而,如果etc或ship是symbolic links,只要plank.txt不是,它就会成功。)
- O_NONBLOCK(如果可能,文件将以非阻塞模式打开。OPEN()调用和任何其他操作都不会导致进程阻塞I/O上的(睡眠)。这种行为只能为FIFO定义。)
- O_SYNC(该文件将为同步I/O打开,在数据被物理写入磁盘之前不会完成写入操作;正常的读取操作已经是同步的,因此标对对读没有影响。)
- O_TRUNC(如果文件存在,它是一个常规文件,并且给定的标志允许写入,该文件将被截断为零长度。在FIFO或终端设备上使用O_TRUNC是被忽略的。用于其他文件类型是未定义的。使用O_RDONLY指定O_TRUNC也是未定义的,因为您需要对文件进行写访问才能截断它。)
int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY);
if(fd == -1){
perror("open");
return -1;
}
close(fd);
return 0;
}

int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY | O_TRUNC);
if(fd == -1){
perror("open");
return -1;
}
close(fd);
return 0;
}

很明显,带有O_TRUNC写文件时的效果就是先把文件先清空,再写入
验证如下
int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY | O_TRUNC);
if(fd == -1){
perror("open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}

int testO_TRUNC()
{
int fd = open("../FileIO/testfile.txt", O_WRONLY | O_TRUNC);
if(fd == -1){
perror("open");
return -1;
}
char buf[5] = "bbbb";
write(fd, buf, 5);
close(fd);
return 0;
}

通过如上的实验,结论得以验证
新文件的所有者
文件所有者的uid是创建文件的进程的uid
默认行为是将文件的gid设置为创建文件的进程的gid。
新文件的权限
之前给的两个关于open函数的调用形式都是有效的。参数mode可以被忽略除非文件是被创建的,也是就说要给出O_CREAT。当你使用O_CREAT时但忘记提供mode参数的时候,那么结果是不明确的,而且非常丑陋──所以不要忘记!
- S_IRWXU 所有者具有读取、写入和执行权限。
- S_IRUSR 所有这具有读取的权限
- S_IWUSR 所有者具有写入的权限
- S_IXUSR 所有者具有执行的权限
- S_IRWXG 组具有读取、写入和执行权限
- S_IRGRP 组具有读取的权限
- S_IWGRP 组具有写入的权限
- S_IXGRP 组具有执行的权限
- S_IRWXO 每个人都可以写入、读取和执行
- S_IROTH 每个人都可以读取
- S_IWOTH 每个人都可以写入
- S_IXOTH 每个人都可以执行
例如,下面的代码打开文件提供的用于写入。如果文件不存在,使用权限0644创建该文件。如果确实存在,则将其截断为零长度:
int testMode()
{
int fd = open("test1.txt", O_WRONLY | O_CREAT | O_TRUNC,
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
// int fd = open("test1.txt", O_CREAT | O_EXCL,
// S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
if(fd == -1){
perror("testMode - open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}
如果此时再用以下代码,则会发现报以下错误:
int testMode()
{
// int fd = open("test1.txt", O_WRONLY | O_CREAT | O_TRUNC,
// S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
int fd = open("test1.txt", O_CREAT | O_EXCL,
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
if(fd == -1){
perror("testMode - open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}

如果此时把文件删除,再次调用以上代码,则会发现:

也就是说明,在文件创建时没有提供写的权限,文件可以创建,但是不会被写入,并且可以看到权限的设置是按照预期的。
最后让我们先删除文件,再加入写的权限并创建文件看一下:
int testMode()
{
// int fd = open("test1.txt", O_WRONLY | O_CREAT | O_TRUNC,
// S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
int fd = open("test1.txt", O_CREAT | O_EXCL | O_WRONLY,
S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP | S_IROTH);
if(fd == -1){
perror("testMode - open");
return -1;
}
char buf[5] = "aaaa";
write(fd, buf, 5);
close(fd);
return 0;
}

我们发现文件按照预期权限创建,并且因为我们在创建文件时加入了写的权限,因此成功写入了想要的内容。