在Kernighan和Ritchie的“The C Programming Language”第二版中,他们实现了UNIX命令ls
的简化版本(第8.6节“示例 – 列表目录” ,第179页)。 为此,他们创build了以下接口,它提供了一个独立于系统的对存储在目录中的文件的名称和inode号的访问。
#define NAME_MAX 14 /* longest filename component; */ /* system dependent */ typedef struct { /* portable director-entry */ long ino; /* inode number */ char name[NAME_MAX+1]; /* name + '\0' terminator */ } Dirent; typedef struct { /* minimal DIR: no buffering, etc. */ int fd; /* file descriptor for directory */ Dirent d; /* the directory entry */ } DIR; DIR *opendir(char *dirname); Dirent *readdir(DIR *dfd); void closedir(DIR *dfd);
然后他们为版本7和系统V UNIX系统实现这个接口。
opendir()
基本上使用系统调用open()
来打开一个目录,而malloc()
为DIR
结构分配空间。 然后由open()
返回的文件描述符存储在该DIR
的variablesfd
中。 没有任何东西存储在Dirent
组件中。
readdir()
使用系统调用read()
获取打开的目录的下一个(系统相关的)目录条目,并将获得的inode号和文件名复制到静态Dirent
结构(返回指针)中。 readdir()
所需的唯一信息是存储在DIR
结构中的文件描述符。
现在我的问题是 :具有DIR
结构的意义何在? 如果我对这个程序的理解是正确的, DIR
的Dirent
组件是不会被使用的,为什么不用一个文件描述符replace整个结构,直接使用open()
和close()
呢?
谢谢。
Ps:我知道,在现代UNIX系统上, read()
不能再用于目录(我已经在Ubuntu 10.04上试过这个程序),但是我仍然要确保在这个例子中我没有忽略一些重要的东西。
从K&R:
遗憾的是,目录的格式和精确内容在所有版本的系统上都不相同。 所以我们将这个任务分成两部分来试图隔离不可移植的部分。 外层定义了一个称为Dirent的结构,以及三个例程opendir , readdir和closedir,以提供对目录条目中名称和inode编号的系统无关的访问。
所以原因是便携性。 他们希望定义一个能够在具有不同统计结构或非标准open()
和close()
系统上生存的接口。 他们继续围绕它构建一系列可重用的工具,甚至不关心它们是否在类Unix系统上。 这是包装的重点。
也许它没有被使用,因为他们通过定义他们的数据结构开始(DIR中有一个Dirent),但最终没有使用它。 保持这样的数据结构是很好的设计。
这样他们就不必为readdir返回的Dirent结构分配内存。 这样,他们可以在分包调用readdir之间重用Dirent。