[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 編程技術 > C/C++ > 正文
在UNIX下對文件與目錄進行編程
本文出自: 作者:wwwunix (2001-06-13 08:10:00)
    近來,隨著UNIX系統的不斷普及,使用UNIX系統的單位和個人也越來越多,特別是Linux的推出,更是風靡全球。基UNIX系統的編程也癒顯重要。本文以一個簡單的程序為例,說明怎樣在UNIX系統下對文件和目錄進行編程。該例是一個類似UNIX系統命令ls的程序,用列出指定的目錄中所有文件和子目錄並計算出指定目錄所用的磁盤空間。

UNIX文件系統簡介 
文件是通過操作系統來管理的。文件的結構以及命名、存取、使用、保護和實現方法都是UNIX系統中的重要內容。總體上,UNIX系統中處理文件的那部分稱為文件系統。同DOS類似,UNIX中的文件系統被組織成樹狀結構。

UNIX中的文件和目錄通過一個9比特的保護碼來進行保護。保護碼分成三個3比特的域,分別對應著文件主、同組用戶和其他用戶。每個域有一位標識讀權限,一位標識寫權限,一位標識執行權限,這三位即rwx位。

在UNIX文件系統中通常包含如下文件類型:

普通文件:一個文件包含所有用戶放在其中的信息。它可以被認為是一個字節序列。它與DOS及WINDOWS系統不同,對每個文件都具有一定的讀寫權限。 
目錄:目錄提供了文件名稱與文件自身之間的映射,由此使得文件系統上的一個結構被作為一個整體對待。一個目錄可包含文件,也可以包含子目錄,這些子目錄同樣可以包含更多的文件和子目錄。一個目錄在被讀的時候,它的行為完全像一個普通文件,但它不能被沒有權限的用戶程序訪問。 
特殊文件:特殊文件是UNIX文件系統中最有特色的地方之一。每個I/O設備(磁盤驅動器、終端等)都與一個這樣的文件有關。對特殊文件的操作和普通文件一樣,但它引發了對相關設備的操作。特殊設備文件的實體保存在目錄/dev中。 
符號鏈接文件:一個符號鏈接在行為上就像指向另一個文件的指針,這有點像C語言中的指針。在文件系統中,實現這一點是建立一個帶有鏈接名稱的文件,該鏈接指向文件的路徑名。 
I標識號,I列表和I節點:一個目錄是由一系列結構組成的,每個結構包含有一個文件名和一個指向文件自身的指針,該指針是一個整數,稱為文件的I標識號。當文件被訪問時,它的I標識號用來作為索引打開一個系統表(I列表),系統表中存放著文件(I節點)的實體。I節點中包含了如下對文件的描述信息: 
.文件自身的用戶和用戶組ID

.文件的保護碼

.文件內容所在的物理磁盤地址

.文件的大小

.最一次I節點改變的時間,最一次使用和最一次修改的時間

.連接該文件的次數,即它出現在其它目錄中的次數

.一個指明文件類型的標記(目錄、普通文件或特殊文件)

有關的系統調用介紹 
lstat系統調用:這是一個非常有用的系統調用,用來獲取存儲在一個I節點上的信息。它接受兩個參數:一個字符串指針,指向說明一個文件的路徑名;另一個是指向stat結構的指針,在這個結構中,存放著有關這個文件的信息。Stat結構包括以下成員: 
st_mode:這個字段包含文件類型和它所具有的訪問權限 
st_ino:這個字段在一個給定的文件系統中唯一的標識了這個文件

st_dev:這個字段唯一地標識了包括這個文件的文件系統

st_rdev:如果I節點是一個特殊設備文件,則這個字段標識設備的類型

st_nlink:文件鏈接的個數

st_uid:文件屬主的用戶ID

st_gid:文件的用戶組的組ID

st_size:文件的字節數

st_atime:文件數據最近一次被訪問的時間

st_mtime:文件數據最近一次被更改的時間

st_ctime:文件狀態最近一次被修改的時間

opendir:它打開一個指定的目錄,並返回一個DIR類型的指針。DIR數據類型包含如下兩個元素: 
d_ino:文件I標識號,如果文件被刪除,則d_ino為0 
d_name:此目錄下包含的文件名

readdir:它讀出指定目錄中的一個文件或子目錄,並將指針移到下一個文件或子目錄。 
closedir:關閉相應的目錄。 
程序說明 
該程序是一個類似UNIX命令ls 的小工具(取文件名為lx,為了簡單起見,此程序只讀取了文件的字節數,即st_size)。它可以接受一個參數:指定的目錄;也可以不帶參數,則默認為當前目錄。程序列出指定目錄及其子目錄中所包含的所有文件的文件名和文件的字節數,並計算出指定目錄所佔磁盤空間的大小。程序詳細說明如下(程序清單見附錄):

1-5行:包含在程序中要用到的一些頭文件。

6行:定義常數TABSPACES為TAB鍵所跳過的空格數,用規整面顯示語句的屏幕格式。

11行:定義一個變量dir_size用存放指定目錄所佔磁盤空間的大小。

12、13行:判斷命令行如果沒有帶參數,則調用list函數,將指定目錄置為當前目錄,並將返回的目錄大小存入變量dir_size中。

14-18行:如果命令行帶的參數大一個,則在屏幕上顯示出此命令的簡要語法並退出程序。

19、20行:如果命令行只帶一個參數,則將此參數作為指定目錄調用list函數,同時也返回目錄的大小並存入變量dir_size中。

21行:打印出指定目錄及其子目錄所佔磁盤空間的大小。

23行:定義list函數,該函數採用遞歸法列出字符串name所指定的目錄及其子目錄中所包含的文件名和文件的大小,並計算name所指定的目錄所佔用的磁盤空間。

26-32行:定義函數中要用的變量並賦初值。

33行:打印當前所操作目錄的目錄名。

34行:開始一個循環次數為2的for循環。第1次循環找出目錄中包含的所有文件,第2次循環找出目錄中包含的所有子目錄。

36-40行:打開指定的目錄,如果打開成功則返回指向此目錄的指針,否則返回NULL。程序打印出出錯信息並退出。

41行:開始一個while循環,每循環一次讀出目錄中的一個文件或子目錄,直到讀出目錄中所有的文件或子目錄,readdir返回NULL表示已讀到此目錄的尾部。

43、44行:判斷讀出的文件的I標識號,如果為0,則表示該文件已被刪除。程序繼續執行並讀取下一個文件。

45-47行:在讀出的文件名前加上絕對或相對路徑,以使程序能正確的從文件系統中訪問指定的文件。

48-52行:調用lstat獲取指定文件的信息,將獲取的信息存儲到結構sbuf中。如果出錯則退出程序。

53行:判斷讀出的文件是否是一個目錄,這個條件用語句(sbuf.st_mode&S_IFMT)==S_IFDIR實現。其它三個條件用濾除符號鏈接、目錄本身和上一級目錄,以避免出現死循環。

55-60行:如果是第2次for循環則遞歸調用list函數,列出相應的子目錄,同時累加目錄所佔磁盤空間的大小。

63-71行:如果是第1次for循環則打印出文件名和文件所佔用的字節數,同時累加所佔磁盤空間的大小。用三條打印語句是因為文件名長度不一致,為了打印出的屏幕美觀。

75行:關閉相應的目錄。

77行:返回本目錄所佔用的磁盤空間。

本程序在Turbo Linux 4.0和FreeBSD 3.0上調試運行通過。

參考資料:《UNIX系統程序員進階》 林新觀編 清華大學出版社

《UNIX系統V/386第4版程序員參考手冊》 電子工業出版社

附錄:程序lx.c

1 #include 

2 #include 

3 #include 

4 #include 

5 #include 

6 #define TABSPACES 8

7 main(argc,argv)

8 int argc;

9 char **argv;

10 {

11 off_t dir_size;

12 if (argc<2)

13 dir_size=list(".");

14 else if (argc>2)

15 {

16 printf("Usage: lx [path]\n");

17 exit(1);

18 }

19 else

20 dir_size=list(argv[1]);

21 printf(" This directory size is %i bytes.\n",dir_size);

22 }

23 off_t list(name)

24 char *name;

25 {

26 char pn[255];

27 DIR *dp;

28 off_t f_size,d_size;

29 int i;

30 struct stat sbuf;

31 struct direct *dir;

32 f_size=0;

33 printf("Current directory is %s\n",name);

34 for (i=0;i<=1;i++)

35 {

36 if ((dp=opendir(name))==NULL)

37 {

38 perror(name);

39 exit(1);

40 }

41 while ((dir=readdir(dp))!=NULL)

42 {

43 if(dir->d_ino==0)

44 continue;

45 strcpy(pn,name);

46 strcat(pn,"/");

47 strcat(pn,dir->d_name);

48 if (lstat(pn,&sbuf)<0)

49 {

50 perror(pn);

51 exit(1);

52 }

53 if 

(((sbuf.st_mode&S_IFMT)!=S_IFLNK)&&((sbuf.st_mode&S_IFMT)==S_IFDIR)&&(strcmp(dir->d_name,".")!=0)&&(strcmp(dir->d_name,"..")!=0))

54 {

55 if (i==1)

56 {

57 d_size=list(pn);

58 f_size=f_size+d_size;

59 }

60 }

61 else

62 {

63 if (i==0)

64 {

65 f_size=f_size+sbuf.st_size;

66 if (strlen(dir->d_name)>=2*TABSPACES)

67 printf("%s\t%i\n",dir->d_name,sbuf.st_size);

68 else if (strlen(dir->d_name)>=TABSPACES)

69 printf("%s\t\t%i\n",dir->d_name,sbuf.st_size);

70 else

71 printf("%s\t\t\t%i\n",dir->d_name,sbuf.st_size);

72 }

73 }

74 }

75 closedir(dp);

76 }

77 return f_size;

78 }

(http://www.fanqiang.com)
    進入【UNIX論壇

相關文章
 

★  樊強制作 歡迎分享  ★