8.3 open、creat、close、unlink
除了默认的标准输入、标准输出和标准错误文件外,其它文件都必须在读或写之前显式地打开
系统调用 open
和 creat
用于实现该功能
open
与第 7 章讨论的 fopen
相似
不同的是,前者返回一个文件描述符,它仅仅只是一个 int
类型的数值,而后者返回一个文件指针
如果发生错误,open
将返回 -1
#include <fcntl.h>
int fd;
int open(char *name, int flags, int perms);
fd = open(name, flags, perms);
与 fopen
一样,参数 name
是一个包含文件名的字符串
第二个参数 flags
是一个 int
类型的值,它说明以何种方式打开文件,主要的几个值如下所示:
O_RDONLY 以只读方式打开文件
O_WRONLY 以只写方式打开文件
O_RDWR 以读写方式打开文件
在 System V UNIX 系统中,这些常量在头文件 <fcntl.h>
中定义
而在 Berkeley(BSD) 版本中则在 <sys/file.h>
中定义
可以使用 fd = open(name, O_RDONLY, 0);
打开一个文件以执行读操作
在本章的讨论中,open
的参数 perms
的值始终为 0
如果用 open
打开一个不存在的文件,则将导致错误
可以使用 creat
系统调用创建新文件或覆盖已有的旧文件,如下所示:
int creat(char *name, int perms);
fd = creat(name, perms);
如果 creat
成功地创建了文件,它将返回一个文件描述符,否则返回 -1
如果此文件已存在,creat
将把该文件的长度截断为 0
,从而丢弃原先已有的内容
使用 creat
创建一个已存在的文件不会导致错误
如果要创建的文件不存在,则 creat
用参数 perms
指定的权限创建文件
在 UNIX 文件系统中,每个文件对应一个 9
比特的权限信息
它们分别控制文件的所有者、所有者组和其他成员对文件的读、写和执行访问
因此,通过一个 3 位的八进制数就可方便地说明不同的权限
例如,0755 说明文件的所有者可以对它进行读、写和执行操作,而所有者组和其他成员只能进行读和执行操作
下面通过一个简化的 UNIX 程序 cp
说明 creat
的用法
该程序将一个文件复制到另一个文件
我们编写的这个版本仅仅只能复制一个文件,不允许用目录作为第二个参数,并且,目标文件的权限不是通过复制获得的,而是重新定义的
#include <stdio.h>
#include <fcntl.h>
#include "syscalls.h"
#define PERMS 0666 /* RW for owner, group, others */
void error(char *, ...);
/* cp: copy f1 to f2 */
main(int argc, char *argv[])
{
int f1, f2, n;
char buf[BUFSIZ];
if (argc != 3)
error("Usage: cp from to");
if ((f1 = open(argv[1], O_RDONLY, 0)) == -1)
error("cp: can't open %s", argv[1]);
if ((f2 = creat(argv[2], PERMS)) == -1)
error("cp: can't create %s, mode %03o", argv[2], PERMS);
while ((n = read(f1, buf, BUFSIZ)) > 0)
if (write(f2, buf, n) != n)
error("cp: write error on file %s", argv[2]);
return 0;
}
该程序创建的输出文件具有固定的权限 0666
利用 8.6 节中将要讨论的 stat
系统调用,可以获得一个已存在文件的模式,并将此模式赋值给它的副本
注意,函数 error
类似于函数 printf
,在调用时可带变长参数表
下面通过 error
函数的实现说明如何使用 printf
函数家族的另一个成员 vprintf
标准库函数 vprintf
函数与 printf
函数类似,所不同的是,它用一个参数取代了变长参数表
且此参数通过调用 va_start
宏进行初始化
同样,vfprintf
和 vsprintf
函数分别与 fprintf
和 sprintf
函数类似
#include <stdio.h>
#include <stdarg.h>
/* error: print an error message and die */
void error(char *fmt, ...)
{
va_list args;
va_start(args, fmt);
fprintf(stderr, "error: ");
vprintf(stderr, fmt, args);
fprintf(stderr, "\n");
va_end(args);
exit(1);
}
一个程序同时打开的文件数是有限制的(通常为 20
)
相应地,如果一个程序需要同时处理许多文件,那么它必须重用文件描述符
函数 close(int fd)
用来断开文件描述符和已打开文件之间的连接,并释放此文件描述符,以供其它文件使用
close
函数与标准库中的 fclose
函数相对应,但它不需要清洗(flush
)缓冲区
如果程序通过 exit
函数退出或从主程序中返回,所有打开的文件将被关闭
函数 unlink(char *name)
将文件 name
从文件系统中删除,它对应于标准库函数 remove