1. 程式人生 > >Linux下DIR,dirent,stat等結構體詳解

Linux下DIR,dirent,stat等結構體詳解

最近在看Linux下檔案操作相關章節,遇到了這麼幾個結構體,被搞的暈乎乎的,今日有空,仔細研究了一下,受益匪淺。

首先說說DIR這一結構體,以下為DIR結構體的定義:

  1. struct __dirstream   
  2.    {   
  3. void *__fd;    
  4. char *__data;    
  5. int __entry_data;    
  6. char *__ptr;    
  7. int __entry_ptr;    
  8. size_t __allocation;    
  9. size_t __size;    
  10.     __libc_lock_define (, __lock)    
  11.    };   
  12. typedefstruct __dirstream DIR;  

DIR結構體類似於FILE,是一個內部結構,以下幾個函式用這個內部結構儲存當前正在被讀取的目錄的有關資訊(摘自《UNIX環境高階程式設計(第二版)》)。函式 DIR *opendir(const char *pathname),即開啟檔案目錄,返回的就是指向DIR結構體的指標,而該指標由以下幾個函式使用:

  1. struct dirent *readdir(DIR *dp);   
  2. void rewinddir(DIR *dp);   
  3. int closedir(DIR *dp);   
  4. long
     telldir(DIR *dp);   
  5. void seekdir(DIR *dp,long loc);  

關於DIR結構,我們知道這麼多就可以了,沒必要去再去研究他的結構成員。

接著是dirent結構體,首先我們要弄清楚目錄檔案(directory file)的概念:這種檔案包含了其他檔案的名字以及指向與這些檔案有關的資訊的指標(摘自《UNIX環境高階程式設計(第二版)》)。從定義能夠看出,dirent不僅僅指向目錄,還指向目錄中的具體檔案,readdir函式同樣也讀取目錄下的檔案,這就是證據。以下為dirent結構體的定義:

  1. struct dirent   
  2. {   
  3. long d_ino; /* inode number 索引節點號 */
  4.     off_t d_off; /* offset to this dirent 在目錄檔案中的偏移 */
  5.     unsigned short d_reclen; /* length of this d_name 檔名長 */
  6.     unsigned char d_type; /* the type of d_name 檔案型別 */
  7. char d_name [NAME_MAX+1]; /* file name (null-terminated) 檔名,最長255字元 */
  8. }  

從上述定義也能夠看出來,dirent結構體儲存的關於檔案的資訊很少,所以dirent同樣也是起著一個索引的作用,如果想獲得類似ls -l那種效果的檔案資訊,必須要靠stat函數了。

通過readdir函式讀取到的檔名儲存在結構體dirent的d_name成員中,而函式

int stat(const char *file_name, struct stat *buf);

的作用就是獲取檔名為d_name的檔案的詳細資訊,儲存在stat結構體中。以下為stat結構體的定義:

  1. struct stat {   
  2.         mode_t     st_mode;       //檔案訪問許可權 
  3.         ino_t      st_ino;       //索引節點號 
  4.         dev_t      st_dev;        //檔案使用的裝置號 
  5.         dev_t      st_rdev;       //裝置檔案的裝置號 
  6.         nlink_t    st_nlink;      //檔案的硬連線數 
  7.         uid_t      st_uid;        //所有者使用者識別號 
  8.         gid_t      st_gid;        //組識別號 
  9.         off_t      st_size;       //以位元組為單位的檔案容量 
  10. time_t     st_atime;      //最後一次訪問該檔案的時間 
  11. time_t     st_mtime;      //最後一次修改該檔案的時間 
  12. time_t     st_ctime;      //最後一次改變該檔案狀態的時間 
  13.         blksize_t st_blksize;    //包含該檔案的磁碟塊的大小 
  14.         blkcnt_t   st_blocks;     //該檔案所佔的磁碟塊 
  15.       };  

這個記錄的資訊就很詳細了吧,呵呵。

最後,總結一下,想要獲取某目錄下(比如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結構卻是要我們自己宣告結構體的。