最近在看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; /* inode number 索引節點號 */
- off_t d_off; /* offset to this dirent 在目錄文件中的偏移 */
- unsigned short d_reclen; /* length of this d_name 文件名長 */
- unsigned char d_type; /* the type of d_name 文件類型 */
- char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最長255字符 */
- }
從上述定義也能夠看出來,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中。
總體就是這樣一種逐步細化的過程,在這一過程中,三種結構體扮演着不同的角色。
- #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結構一樣,在打開一個目錄的時候,由內核幫我們分配該結構體的內存。