Chinaunix首页 | 论坛 | 博客
  • 博客访问: 103631971
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: C/C++

2008-04-16 23:01:17

第四章 文件与目录编程

4.1 基本概念

·文件目录概述

文件系统是UNIX对计算机技术的一大贡献!UNIX系统的文件管理十分灵活、功能强大,许多首次在UNIX系统中出现的概念被其他操作系统所采用,如MS-DOS等。

UNIX系统提供了一种层次目录方案。目录就象存放一组文件的柜子一样,目录也可以包括在其他目录中,这样就形成了一种庞大的、具有分支的组织方式,这种结构通常被称为树状结构。目录实际上也是一种特殊的文件。命令、数据文件、其他命令甚至设备(特别文件)都可以作为目录中的项(文件)。

·I标识号、I列表和I节点
一个目录是由一系列结构组成的;每个结构包含一个文件名和一个指向文件自身的指针,该指针是一个整数,称为文件的I标识号。当文件被访问时,它的I标识号用来作为索引打开一个系统表(I列表),系统中存放着文件(I节点)的实体。I节点包含了对文件的描述:
·文件自身的用户和用户组ID
·文件的保护码
·文件内容所在的物理磁盘地址
·文件的大小
·最后一次I节点改变的时间,最后一次使用和修改的时间
·连接该文件的次数,即它出现在其他目录中的次数
·一个指明文件类型的标记(目录、普通文件、特别文件)
·文件的三级保护

UNIX把使用文件的用户分成三个等级:文件所有者、同组用户和其他用户。文件所有者也称文件主,是文件的创建者,对该文件拥有所有权限;同组用户是具有相同组标识号的所有用户,文件主可以决定一个文件属于哪个组以及该组用户对文件的存取权;其他用户是指与文件主无关的用户,他们与文件主不属于同一个用户组,其他用户对一个文件的访问权限也由该文件主决定的。

一个文件的访问权限存放在该文件I节点的di_mode域中,di_mode的0-8位表示文件主、文件组用户和其他用户对该文件的存取权限。举个例子,用"ls -l"命令可列出文件hello.c的模式和属性:

-rwxr-xr-x 1 yds user 58 9月 25日 10时54分 hello.c

最左面一栏显示了该文件的模式:文件主对该文件可读(r)、可写(w)、可执行(x),同组用户对该文件可读、可执行,其他用户对该文件可读、可执行。相应的,di_mode的0-8位为111101101(0755)。

4.2 文件编程介绍

·检查访问权限-access系统调用

access系统调用的格式为:

#include
int access(const char *path, int amode);

其中:参数path指出被检查文件的路径,参数amode指出访问权限。Access判断调用进程的实际用户对文件path是否具有amode所指定的访问权限,若有相应权限,access返回0,否则返回-1。

参数amode可取以下值或它们的逻辑"或":
R_OK 检查读权限
W_OK 检查写权限
X_OK 检查执行(搜索)权限
F_OK 检查文件是否存在

例如:access("hello.c", R_OK|W_OK), 用来检查实际用户对文件hello.c是否具有读/写权;access("hello.c",F_OK) 判断文件hello.c是否存在。

·链接与删除文件-link和unlink系统调用

link和unlink系统调用的格式为:

#include
int link (const char *path1, const char *path2);
int unlink(const char *path);

其中:参数path1指出已经存在的要被链接的文件路径名,path2指出要建立的链接文件。link实现path2到path1的链接,相当于给path1起了一个别名,同时文件path1的链接计数加1。若成功则返回0,否则返回-1。

参数path指出要被删除的文件路径名。Unlink删除由path指出的文件,若成功则返回0,否则返回-1。

·从I节点上获取信息-stat与fstat系统调用

stat与fstat的调用格式为:

#include
#include
int stat(const char *path, struct stat *buf);
int fstat(int fildes, struct stat *buf);

说明:stat和fstat都用于获取文件I节点中有关状态信息。stat根据参数path给出的文件路径名,搜索它对应的盘I节点,而fstat则根据参数fildes给出的文件描述字去查找对应的I节点。这两个调用都把从I节点中获取到的信息重组后放入参数buf指向的stat结构中(stat结构的说明在文件/usr/include/sys/stat.h中)。这两个调用成功时均返回0,否则返回-1。

stat与fstat调用无论在使用上还是在功能上都是非常类似的,在参数上有一点区别。下面我们来看一个例子。

/* statfile.c */
#include
#include
#include
#include

main(argc,argv)
int argc;
char *argv[];
{
int fd;
struct stat statbuf;
if (argc!=2){
printf("usage: statfile filename!\n");
exit(1);
}
if ((fd = fopen(argv[1], O_RDONLY)) == -1)
fprintf(stderr, "Cannot open %s!\n", argv[1]);
if (unlink(argv[1]) == -1)
fprintf(stderr,"Cannot unlink %s!\n", argv[1]);
if (stat(argv[1], &statbuf) == -1) /* by file name */
fprintf(stderr, "stat %s fails as it should !\n");
else
printf("stat %s succeed!\n", argv[1]);
if (fstat(fd, &statbuf) == -1) /* by file descriptor */
fprintf(stderr, "fstat %s fails!\n", argv[1]);
else
printf("fstat %s succeeds as it should!\n", argv[1]);
}

程序首先打开命令行中指定的文件,然后用unlink将该文件删除,接着分别用stat与fstat系统调用获取该文件的信息。假设当前命令下有一个名为xxx.c的文件,运行

%statfile xxx.c

后,将会输出如下结果:

stat xxx.c fails as it should!
fstat xxx.c succeeds as it should!

从中可知,当一个打开文件被删除后,用stat无法获取该文件的信息。而fstat就可获取该文件的信息。这是由于文件名在unlink之后已从目录中除去,无法找到该文件名,而文件描述字则因文件仍打开而保存下来。因此stat不能成功返回,但fstat仍可成功返回。

使用stat调用来判定一个文件为何种文件类型时相当有用。例如下列代码:

stat("hello", &statbuf);
if (statbuf.st_mod & S_IFMT) == S_IFDIR)
printf("This is a directory file!\n");
else if (statbuf.st_mod & S_IFMT) == S_IFREG)
printf("This is a regular file !\n");
else …

以上代码可判定当前目录下的hello文件是否为目录文件或其他类型的文件。

4.3 目录编程介绍

UNIX把目录也视为一种文件,称为目录文件,并同普通文件一样进行管理和保护。如open、close、read、lseek等文件操作对目录文件都是有效的。前面讲到的文件编程中的各个系统调用对于目录来说也同样有效。但是与普通文件相比目录文件又具有自身的一些特点:

目录文件的读/写/执行访问权限有特殊的含义:读权限允许用户读取目录项的内容;写权限允许用户创建或删除一个文件;执行权限则允许用户检索目录(此时通常称为目录搜索权限)。

目录的创建、删除与普通文件也不同,另外,任何用户都不能对目录文件以写方式打开进行文件写操作。

·目录的创建和删除-mkdir和rmdir系统调用

mkdir 和rmdir系统调用的格式为:

#include
#include
int mkdir (const char *path, mode_t mode);

#include
int rmdir(const char *path);

其中:参数path分别指出要创建和删除的目录文件的文件名。mkdir调用中的参数mode指出新创建目录文件的文件模式。新创建目录后,除"."和".."两项外,无别的目录项;删除目录时,要求目录中除"."和".."两项外,也无别的目录项。这两个系统调用Access成功时都返回0,否则返回-1。

·目录的读取-opendir/readdir/closedir库函数

目录文件可以像普通文件一样,先用系统调用open以读方式打开,再用read调用读取其中的内容。同时,由于目录文件是由具有目录结构的目录项组成的,用read读取其内容有些不方便。UNIX提供的库函数opendir/readdir/closedir等可以方便地实现目录读取。函数说明如下:

#include
#include
DIR *opendir(char *filename);
struct direct *readdir(DIR *dirp);
void closedir(DIR *dirp);

说明:参数filename指出要打开的目录路径名,库函数opendir返回一个指向结构DIR(在文件/usr/include/sys/dir.h中定义)的指针。库函数readdir和closedir均以这个指针作为参数,其中readdir返回一个指向结构direct的指针。有关目录的操作均可基于这个指针。下面是一个例子,查找当前目录下文件名为"name"的文件。

len = strlen(name);
dirp = opendir(".");
if (dirp == NULL) {
return NOT_FOUND;
}
while ((dp = readdir(dirp)) != NULL) {
if (dp->d_namlen == len && !strcmp(dp->d_name, name)) {
closedir(dirp);
return FOUND;
}
}
closedir(dirp);
return NOT_FOUND;

库函数closedir关闭打开的目录。值得注意的是,上面这一小段代码在编程中很实用,稍加修改即可实现UNIX下类似"ls"的简单命令。
阅读(412) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~