最近在看Linux下文件操作相关章节,遇到了这么几个结构体,被搞的晕乎乎的,今日有空,仔细研究了一下,受益匪浅。
首先说说DIR这一结构体,以下为DIR结构体的定义:
- struct __dirstream
- {
- void *__fd;
- char *__data;
- int __entry_data;
- char *__ptr;
- int __entry_ptr;
- size_t __allocation;
- size_t __size;
- __libc_lock_define (, __lock)
- };
-
- typedef struct __dirstream DIR;
DIR结构体类似于FILE,是一个内部结构,以下几个函数用这个内部结构保存当前正在被读取的目录的有关信息(摘自《UNIX环境高级编程(第二版)》)。函数 DIR *opendir(const char *pathname),即打开文件目录,返回的就是指向DIR结构体的指针,而该指针由以下几个函数使用:
- struct dirent *readdir(DIR *dp);
-
- void rewinddir(DIR *dp);
-
- int closedir(DIR *dp);
-
- long telldir(DIR *dp);
-
- void seekdir(DIR *dp,long loc);
关于DIR结构,我们知道这么多就可以了,没必要去再去研究他的结构成员。
接着是dirent结构体,首先我们要弄清楚目录文件(directory file)的概念:这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针(摘自《UNIX环境高级编程(第二版)》)。从定义能够看出,dirent不仅仅指向目录,还指向目录中的具体文件,readdir函数同样也读取目录下的文件,这就是证据。以下为dirent结构体的定义:
- struct dirent
- {
- long d_ino;
-
- off_t d_off;
-
- unsigned short d_reclen;
-
- unsigned char d_type;
-
- char d_name [NAME_MAX+1];
- }
从上述定义也能够看出来,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似ls -l那种效果的文件信息,必须要靠stat函数了。
通过readdir函数读取到的文件名存储在结构体dirent的d_name成员中,而函数
int stat(const char *file_name, struct stat *buf);
的作用就是获取文件名为d_name的文件的详细信息,存储在stat结构体中。以下为stat结构体的定义:
- struct stat {
-
- mode_t st_mode;
-
- ino_t st_ino;
-
- dev_t st_dev;
-
- dev_t st_rdev;
-
- nlink_t st_nlink;
-
- uid_t st_uid;
-
- gid_t st_gid;
-
- off_t st_size;
-
- time_t st_atime;
-
- time_t st_mtime;
-
- time_t st_ctime;
-
- blksize_t st_blksize;
-
- blkcnt_t st_blocks;
-
- };
这个记录的信息就很详细了吧,呵呵。
最后,总结一下,想要获取某目录下(比如a目下)b文件的详细信息,我们应该怎样做?
首先,我们使用opendir函数打开目录a,返回指向目录a的DIR结构体c。
接着,我们调用readdir( c)函数读取目录a下所有文件(包括目录),返回指向目录a下所有文件的dirent结构体d。
然后,我们遍历d,调用stat(d->name,stat *e)来获取每个文件的详细信息,存储在stat结构体e中。
总体就是这样一种逐步细化的过程,在这一过程中,三种结构体扮演着不同的角色。
---------------------------------------------------------------------华丽丽的分割线---------------------------------------------------------------------------------------------------------------------------------------------
补充:
首先,关于上文提到的“
DIR结构体类似于FILE,是一个内部结构”此句中的内部结构不是很明白,后来看到一遍博文有介绍FILE结构,具体如下:
博文地址: 点击打开链接
“
struct file结构体定义在include/linux/fs.h中定义。文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,struct file的指针通常被命名为file或filp。”
此处说FILE结构是在内核打开文件时创建的。参考以前的关于FILE操作的代码可以发现,我们在使用FILE结构时是直接声明一个FILE结构的指针,例如:
FILE *fp
然后使用fopen函数返回一个FILE结构指针给fp。我们并没有声明一个结构体,而只是声明该结构体的指针。
所以本人猜测,具体的结构体的内存分配已经由内核帮我们完成了。
DIR结构的使用方法和FILE类似,在《Linux程序设计第四版》的P104有一个打印目录下所有文件及目录的程序,代码如下:
- #include <unistd.h>
- #include <stdio.h>
- #include <dirent.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <stdlib.h>
-
-
- void printdir(char *dir, int depth)
- {
- DIR *dp;
- struct dirent *entry;
- struct stat statbuf;
-
- if ((dp = opendir(dir)) == NULL) {
- fprintf(stderr, "Can`t open directory %s\n", dir);
- return ;
- }
-
- chdir(dir);
- while ((entry = readdir(dp)) != NULL) {
- lstat(entry->d_name, &statbuf);
- if (S_ISDIR(statbuf.st_mode)) {
- if (strcmp(entry->d_name, ".") == 0 ||
- strcmp(entry->d_name, "..") == 0 )
- continue;
- printf("%*s%s/\n", depth, "", entry->d_name);
- printdir(entry->d_name, depth+4);
- } else
- printf("%*s%s\n", depth, "", entry->d_name);
- }
- chdir("..");
- closedir(dp);
- }
-
-
- int main(int argc, char *argv[])
- {
- char *topdir = ".";
- if (argc >= 2)
- topdir = argv[1];
-
- printf("Directory scan of %s\n", topdir);
- printdir(topdir, 0);
- printf("done.\n");
- exit(0);
- }
在这个程序中我们使用的DIR结构也只是声明了该结构的指针,那么DIR结构应该也是同FILE结构一样,在打开一个目录的时候,由内核帮我们分配该结构体的内存。
dirent结构也是如此。但stat结构却是要我们自己声明结构体的。