色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

UNIX 文件系統(tǒng)基本操作

瀏覽:6日期:2024-06-12 15:22:24

本文示例源代碼或素材下載

引言

Unix® 中任何事物都是文件 的觀點(diǎn)意味著,您將始終會(huì)與文件和目錄打交道,無(wú)論您開(kāi)發(fā)的是何種類(lèi)型的應(yīng)用程序。任何事物都存儲(chǔ)為文件,從數(shù)據(jù)到配置文件、甚至是設(shè)備,在對(duì) UNIX 編程經(jīng)過(guò)幾個(gè)小時(shí)的學(xué)習(xí)之后,stdio.h 系統(tǒng) Header 中的函數(shù)將能夠?yàn)槟峁┖芎玫膸椭?/p>

一個(gè)時(shí)常困擾 UNIX 編程新手的問(wèn)題是,如何瀏覽一個(gè)目錄,并對(duì)其中的文件、目錄和符號(hào)鏈接進(jìn)行相應(yīng)的處理。如何能夠獲取它們的列表,以及如何能夠確定它們究竟是什么?

請(qǐng)繼續(xù)閱讀本文,以學(xué)習(xí)如何使用 dirent.h 函數(shù)系列 (opendir()/readdir()/closedir()) 來(lái)讀取目錄中的條目,以及使用 stat() 函數(shù)來(lái)確定這些條目所對(duì)應(yīng)的內(nèi)容。

開(kāi)始之前

本文中的示例代碼(請(qǐng)參見(jiàn)下載)使用 C/C++ 開(kāi)發(fā)工具 (CDT) 在 Eclipse 3.1 中編寫(xiě),readdir_demo 項(xiàng)目是一個(gè)托管的 Make 項(xiàng)目,該項(xiàng)目通過(guò)使用 CDT 程序生成規(guī)則構(gòu)建。您在這個(gè)項(xiàng)目中找不到 Makefile,但是它們非常簡(jiǎn)單,如果需要在 Eclipse 之外編譯這些代碼,您可以很容易地生成相應(yīng)的 Makefile。

如果您還沒(méi)有嘗試使用 Eclipse,那么您真的應(yīng)該試一試。它是一個(gè)非常好的集成開(kāi)發(fā)環(huán)境 (IDE),并且隨著發(fā)行版本的不斷更新,它變得更加完善。它來(lái)自于生命力頑強(qiáng)的 EMacS 以及基于 Makefile 的開(kāi)發(fā)工具。請(qǐng)參閱本文結(jié)尾處的參考資料部分,其中提供了一些很好的 Eclipse 文章的鏈接。

讀取目錄條目

對(duì)于一個(gè)給定路徑的目錄,應(yīng)該如何讀取其中的條目呢?您無(wú)法像操作文件那樣打開(kāi)目錄(使用 open() 或 fopen() 函數(shù)),并且即便可以這樣做,所得到的數(shù)據(jù)可能是您正在使用的文件系統(tǒng)的專用格式,而對(duì)于不十分熟悉的程序員來(lái)說(shuō),直接訪問(wèn)這些數(shù)據(jù)將使情況變得更糟。

dirent.h 函數(shù),opendir()、readdir() 和 closedir(),它們正是您所需要的。這些函數(shù)的使用與用來(lái)對(duì)文件進(jìn)行操作的 open/read/close 的習(xí)慣用法非常相似,但有一點(diǎn)除外:對(duì)于每個(gè)目錄條目,readdir() 函數(shù)一次返回一個(gè)指向特殊結(jié)構(gòu)(struct dirent 類(lèi)型)的指針。通常,對(duì)目錄進(jìn)行瀏覽類(lèi)似于清單 1 中所示的偽代碼。

清單 1. 讀取目錄中的內(nèi)容

dir = opendir( "some/path/name" )entry = readdir( dir )while entry is not NULL:do_something_with( entry )entry = readdir( dir )closedir( dir )

在出現(xiàn)問(wèn)題時(shí),opendir() 和 readdir() 函數(shù)都會(huì)返回 NULL,并且將設(shè)置全局變量 errno 的值,以指出所出現(xiàn)的錯(cuò)誤。如果 readdir() 返回 NULL,并且 errno 為 0(有時(shí)也稱為 EOK 或 ENOERROR),則表示沒(méi)有其他的目錄條目。

有一點(diǎn)需要注意,每個(gè)目錄都包含“.(對(duì)該目錄的引用)和“..(對(duì)該目錄的父目錄的引用)條目。根據(jù)您所進(jìn)行的操作,可能需要忽略對(duì)這些條目的處理。

請(qǐng)注意,readdir() 不是線程安全的,因?yàn)樗祷氐慕Y(jié)構(gòu)是存儲(chǔ)在函數(shù)庫(kù)中的一個(gè)靜態(tài)變量。大多數(shù)現(xiàn)代的 Unix 系統(tǒng)都具有線程安全的 readdir_r(),如果您正在編寫(xiě)線程代碼,可以使用這個(gè)函數(shù)作為替代。

struct dirent 中包含了哪些內(nèi)容呢?

POSIX 1003.1 標(biāo)準(zhǔn)僅僅為 struct dirent 定義了一個(gè)必需的條目,即 char 數(shù)組 d_name。這是用標(biāo)準(zhǔn)的以 NULL 結(jié)尾的字符串表示的該條目的名稱。這個(gè)結(jié)構(gòu)中任何其他內(nèi)容都是特定于您的 UNIX 系統(tǒng)的。

的確如此,struct dirent 中其他所有內(nèi)容 都是不可移植的。嚴(yán)格滿足一致性的系統(tǒng)不應(yīng)該在其中包含任何其他的內(nèi)容。如果您編寫(xiě)了使用額外結(jié)構(gòu)成員的代碼,那么您必須將其標(biāo)記為不可移植的,并且包含一個(gè)完成相同任務(wù)的替換代碼路徑,如果您認(rèn)為這樣做特別友好的話。

例如,許多 Unix 包含一個(gè) d_type 成員和一些附加常量,這樣一來(lái),您無(wú)需額外的 stat() 調(diào)用就可以檢查目錄條目的類(lèi)型。除了減少另外的系統(tǒng)調(diào)用之外,這種不可移植的擴(kuò)展還減少了從文件系統(tǒng)獲取更多元數(shù)據(jù)的開(kāi)銷(xiāo)非常高的訪問(wèn)操作。眾所周知,在大多數(shù) UNIX 上,stat() 函數(shù)的執(zhí)行速度非常慢。

獲取文件信息

除了獲取目錄中條目的名稱之外,您可能還需要一些附加信息,以確定下一步要進(jìn)行的操作。至少,僅根據(jù)目錄條目的名稱,您無(wú)法辨別文件條目。

stat() 函數(shù)會(huì)將特定文件的相關(guān)信息填入 struct stat 結(jié)構(gòu)中,如果您獲得的是文件描述符而不是文件名,那么作為替代,您可以使用 fstat() 函數(shù)。如果您想能夠檢測(cè)出符號(hào)鏈接,那么可以對(duì)文件名使用 lstat()。

與 readdir() 返回的 struct dirent 不同,struct stat 具有相當(dāng)多的標(biāo)準(zhǔn)的、必需的成員:

st_mode——文件權(quán)限(用戶、其他用戶、組)和標(biāo)志

st_ino——文件序列號(hào)

st_dev——文件設(shè)備號(hào)

st_nlink——文件連接計(jì)數(shù)

st_uid——所有者用戶 ID

st_gid——所有者組 ID

st_size——以字節(jié)表示的文件大小(針對(duì)普通文件)

st_atime——最后的訪問(wèn)時(shí)間

st_mtime——最后的修改時(shí)間

st_ctime——文件的創(chuàng)建時(shí)間

對(duì) st_mode 成員使用 S_*() 宏,這樣就可以找出您所處理的目錄條目的類(lèi)型:

S_ISBLK(mode)——是否為塊特殊文件?(通常是某種基于塊的設(shè)備)

S_ISCHR(mode)——是否為字符特殊文件?(通常是某種基于字符的設(shè)備)

S_ISDIR(mode)——是否為目錄?

S_ISFIFO(mode)——是否為管道或 FIFO 特殊文件?

S_ISLNK(mode)——是否為符號(hào)鏈接?

S_ISREG(mode)——是否為普通文件?

眾所周知,在大多數(shù)文件系統(tǒng)上,stat() 函數(shù)的執(zhí)行速度非常慢,所以如果您打算在將來(lái)再次使用該信息,可能需要對(duì)其進(jìn)行緩存。

關(guān)于符號(hào)鏈接的說(shuō)明

通常,您并不關(guān)心符號(hào)鏈接。如果對(duì)符號(hào)鏈接調(diào)用 stat(),那么您將獲取該鏈接所指向的文件的相關(guān)信息。這和用戶的體驗(yàn)是一致的,因?yàn)榭刂婆c該文件交互的是目標(biāo)文件的權(quán)限,而不是符號(hào)鏈接本身。

有些應(yīng)用程序,如 ls 和備份程序,需要能夠顯示鏈接文件本身的相關(guān)信息,例如它所指向的文件。當(dāng)您使用 lstat() 來(lái)代替 stat() 時(shí),以及當(dāng)您出于特定的目的而需要獲取符號(hào)鏈接本身的相關(guān)信息,而不是直接與其鏈接的文件打交道時(shí),情況也是這樣的。

將其組合在一起

既然已經(jīng)學(xué)習(xí)了如何使用 readdir() 和 stat() 來(lái)查找目錄中的條目,那么讓我們來(lái)看看演示這些函數(shù)的一些實(shí)際代碼。

這里所介紹的代碼將瀏覽命令行中指定的一個(gè)或多個(gè)目錄,并顯示在該目錄中找到的每個(gè)條目的相關(guān)信息。當(dāng)它找到另一個(gè)目錄時(shí),它會(huì)對(duì)該目錄進(jìn)行同樣的處理。對(duì)于符號(hào)鏈接,將顯示其目標(biāo)文件,并且還將顯示普通文件的大小。將忽略特殊文件。

如清單 2 所示,這個(gè)簡(jiǎn)單的演示應(yīng)用程序中包含了各種 Header 文件。程序的開(kāi)始?jí)K中包含了大多數(shù)程序中使用的標(biāo)準(zhǔn)部分,并且后面的四項(xiàng)是在該程序中使用 readdir() 和 stat() 所必需的。

清單 2. Header 和常量

#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <limits.h>#include <sys/types.h>#include <sys/stat.h>#include <dirent.h>#include <unistd.h>

process_Directory() 函數(shù)(開(kāi)始于清單 3,結(jié)束于清單 6)讀取了指定的目錄,并顯示了每個(gè)條目的相關(guān)信息。opendir() 返回的 DIR 指針與 fopen() 返回的 FILE 指針類(lèi)似,它是一個(gè)用于跟蹤目錄流的操作系統(tǒng)特定的對(duì)象,您應(yīng)該忽略其具體內(nèi)容。

清單 3. 處理一個(gè)目錄

unsigned process_directory( char *theDir ){DIR *dir = NULL;struct dirent entry;struct dirent *entryPtr = NULL;int retval = 0;unsigned count = 0;char pathName[PATH_MAX + 1];/* Open the given directory, if you can. */ dir = opendir( theDir );if( dir == NULL ) {printf( "Error opening %s: %s", theDir, strerror( errno ) );return 0;}

在打開(kāi)了指定的目錄之后,調(diào)用 readdir_r()(請(qǐng)參見(jiàn)清單 4)以獲取關(guān)于第一個(gè)條目的信息,隨后每次調(diào)用 readdir_r() 都將返回下一個(gè)條目,直到到達(dá)了目錄末尾,并且 entryPtr 被設(shè)置為 NULL。這里還使用了 strncmp() 來(lái)檢查“.和“..條目,以便略過(guò)它們。如果不略過(guò)它們,您將永遠(yuǎn)都在處理類(lèi)似“theDir/./././././././././.等這樣的目錄。

清單 4. 讀取一個(gè)目錄條目

retval = readdir_r( dir, &entry, &entryPtr );while( entryPtr != NULL ) {struct stat entryInfo;if( ( strncmp( entry.d_name, ".", PATH_MAX ) == 0 ) ||( strncmp( entry.d_name, "..", PATH_MAX ) == 0 ) ) {/* Short-circuit the . and .. entrIEs. */retval = readdir_r( dir, &entry, &entryPtr );continue;}

既然已經(jīng)得到了目錄的條目名稱,那么您需要構(gòu)造一個(gè)更加完整的路徑(請(qǐng)參見(jiàn)清單 5),然后調(diào)用 lstat() 以獲取該條目的相關(guān)信息。因?yàn)榉?hào)鏈接需要特殊的處理,所以這里使用了 lstat() 函數(shù)。您可以使用 readlink() 函數(shù)找到其目標(biāo)文件。

如果該條目是一個(gè)目錄,那么對(duì)這個(gè)目錄遞歸地調(diào)用 process_Directory(),并將其中所找到的條目數(shù)加到運(yùn)行總數(shù)中。如果該條目是一個(gè)文件,那么顯示其名稱和字節(jié)數(shù)(可在 struct stat 的 st_size 成員中找到)。

清單 5. 處理?xiàng)l目

(void)strncpy( pathName, theDir, PATH_MAX );(void)strncat( pathName, "/", PATH_MAX );(void)strncat( pathName, entry.d_name, PATH_MAX );if( lstat( pathName, &entryInfo ) == 0 ) {/* stat() succeeded, let's party */count++;if( S_ISDIR( entryInfo.st_mode ) ) {/* directory */printf( "processing %s/n", pathName );count += process_directory( pathName );} else if( S_ISREG( entryInfo.st_mode ) ) {/* regular file */printf( "t%s has %lld bytesn",pathName, (long long)entryInfo.st_size );} else if( S_ISLNK( entryInfo.st_mode ) ) {/* symbolic link */char targetName[PATH_MAX + 1];if( readlink( pathName, targetName, PATH_MAX ) != -1 ) {printf( "t%s -> %sn", pathName, targetName );} else {printf( "t%s -> (invalid symbolic link!)n",pathName );}}} else {printf( "Error statting %s: %sn", pathName, strerror(errno ) );}

在 while 循環(huán)的底部,讀取另一個(gè)目錄條目并對(duì)其進(jìn)行處理。如果您完成了對(duì)目錄條目的處理,那么關(guān)閉當(dāng)前打開(kāi)的目錄,并返回經(jīng)過(guò)處理的條目的數(shù)目。

清單 6. 讀取另一個(gè)條目

retval = readdir_r( dir, &entry, &entryPtr );}/* Close the Directory and return the number of entrIEs. */(void)closedir( dir );return count;}

最后,清單 7 顯示了該程序的 main() 函數(shù),它只是對(duì)命令行中傳遞的每個(gè)參數(shù)調(diào)用了 process_directory() 函數(shù)。一個(gè)真正的程序應(yīng)該具有使用方法消息,并且在用戶沒(méi)有指定任何參數(shù)時(shí),提供某種形式的反饋信息,但我把這項(xiàng)內(nèi)容作為練習(xí)留給讀者。

清單 7. 主線

/* readdir_demo main()** Run through the specified directories, and pass them* to process_directory().*/int main( int argc, char **argv ){int idx = 0;unsigned count = 0;for( idx = 1; idx < argc; idx++ ) {count += process_directory( argv[idx] );}return EXIT_SUCCESS;}

這就是整個(gè)程序。盡管包含了較多的文件,但處理目錄條目并不是十分困難。

結(jié)束語(yǔ)

使用 readdir() 和 stat() 函數(shù)瀏覽目錄中的條目并確定對(duì)其進(jìn)行的額外處理,是非常簡(jiǎn)單的,在您需要列舉目錄中的內(nèi)容時(shí),也可能會(huì)使用到這種處理方法。它是一種很實(shí)用的方法,但是對(duì)于一些沒(méi)有經(jīng)驗(yàn)的 Unix 開(kāi)發(fā)人員來(lái)說(shuō),卻難以掌握。本文的目的是降低其難度,使得 UNIX 開(kāi)發(fā)人員能夠充分利用這些有價(jià)值的函數(shù)。

標(biāo)簽: Unix系統(tǒng)
主站蜘蛛池模板: 亚洲国产日韩欧美在线 | 国产伦精品一区三区视频 | 久久国产免费一区二区三区 | 精品国产免费观看一区 | 成人精品一区二区三区 | 亚洲免费看片 | 91久久线看在观草草青青 | 中国美女一级黄色片 | 久久久国产一区二区三区 | 女人让男人桶的小视频 | 国产精品国产三级国产专播 | 黄色在线播放 | 久久五月女厕所一区二区 | 一级毛片不卡免费看老司机 | 欧美国产成人免费观看永久视频 | 国产一级毛片外aaaa | 欧美激情中文字幕 | 欧美a在线看| 成人免费xxxxx在线视频 | 日韩欧美精品一区二区三区 | 日本一区二区三区不卡在线视频 | 欧美成人亚洲综合精品欧美激情 | 免费香蕉成视频成人网 | 日本a一级片 | 在线播放性xxx欧美 在线播放亚洲视频 | 日韩精品中文字幕一区三区 | 国产精品久久毛片蜜月 | 免费毛片儿 | 国产在线观看一区二区三区四区 | 在线观看精品视频一区二区三区 | 亚洲午夜影视 | 一级特黄一欧美俄罗斯毛片 | 香港三级日本三级妇人三级 | 女人被男人躁得好爽免费文 | 国产成人久久精品二区三区 | 婷婷在线成人免费观看搜索 | 国产大片免费天天看 | 亚洲区精品 | 日本特黄乱人伦片 | 久久精品久久精品国产大片 | 偷拍精品视频一区二区三区 |