10.3 打开和关闭文件

进程是通过调用 open 函数来打开一个已存在的文件或者创建一个新文件的:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(char *filename, int flags, mode_t mode);

// 返回:若成功则为新文件描述符,若出错为 -1。

open 函数将 filename 转换为一个文件描述符,并且返回描述符数字。返回的描述符总是在进程中当前没有打开的最小描述符。flags 参数指明了进程打算如何访问这个文件:

  • O_RDONLY:只读。

  • O_WRONLY:只写。

  • O_RDWR:可读可写。

例如,下面的代码说明如何以读的方式打开一个已存在的文件:

fd = Open("foo.txt", O_RDONLY, 0);

flags 参数也可以是一个或者更多位掩码的或,为写提供给一些额外的指示:

  • O_CREAT:如果文件不存在,就创建它的一个截断的(truncated)(空)文件。

  • O_TRUNC:如果文件已经存在,就截断它。

  • O_APPEND:在每次写操作前,设置文件位置到文件的结尾处。

例如,下面的代码说明的是如何打开一个已存在文件,并在后面添加一些数据:

fd = Open("foo.txt", O_WRONLY|O_APPEND, 0);

mode 参数指定了新文件的访问权限位。这些位的符号名字如图 10-2 所示。

掩码

描述

S_IRUSR

使用者(拥有者)能够读这个文件

S_IWUSR

使用者(拥有者)能够写这个文件

S_IXUSR

使用者(拥有者)能够执行这个文件

S_IRGRP

拥有者所在组的成员能够读这个文件

S_IWGRP

拥有者所在组的成员能够写这个文件

S_IXGRP

拥有者所在组的成员能够执行这个文件

S_IROTH

其他人(任何人)能够读这个文件

S_IWOTH

其他人(任何人)能够写这个文件

S_IXOTH

其他人(任何人)能够执行这个文件

图 10-2 访问权限位。在 sys/stat.h 中定义

作为上下文的一部分,每个进程都有一个 umask,它是通过调用 umask 函数来设置的。当进程通过带某个 mode 参数的 open 函数调用来创建一个新文件时,文件的访问权限位被设置为 mode & ~umask。例如,假设我们给定下面的 mode 和 umask 默认值:

#define DEF_MODE   S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
#define DEF_UMASK  S_IWGRP|S_IWOTH

接下来,下面的代码片段创建一个新文件,文件的拥有者有读写权限,而所有其他的用户都有读权限:

umask(DEF_UMASK);
fd = Open("foo.txt", O_CREAT|O_TRUNC|O_WRONLY, DEF_MODE);

最后,进程通过调用 close 函数关闭一个打开的文件。

#include <unistd.h>

int close(int fd);

// 返回:若成功则为 0,若出错则为 -1。

关闭一个已关闭的描述符会出错。

练习题 10.1

下面程序的输出是什么?

#include "csapp.h"

int main()
{
    int fd1, fd2;

    fd1 = Open("foo.txt", O_RDONLY, 0);
    Close(fd1);
    fd2 = Open("baz.txt", O_RDONLY, 0);
    printf("fd2 = %d\n", fd2);
    exit(0);
}

Unix 进程生命周期开始时,打开的描述符赋给了 stdin(描述符 0)、stdout(描述符 1)和 stderr(描述符 2)。open 函数总是返回最低的未打开的描述符,所以第一次调用。pen 会返回描述符 3。调用 close 函数会释放描述符 3。最后对 open 的调用会返回描述符 3,因此程序的输出是 “fd2=3”。

最后更新于