电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

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

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

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

引言

Unix® 中任何事物都是文件 的觀點意味著,您將始終會與文件和目錄打交道,無論您開發(fā)的是何種類型的應用程序。任何事物都存儲為文件,從數(shù)據(jù)到配置文件、甚至是設備,在對 UNIX 編程經(jīng)過幾個小時的學習之后,stdio.h 系統(tǒng) Header 中的函數(shù)將能夠為您提供很好的幫助。

一個時常困擾 UNIX 編程新手的問題是,如何瀏覽一個目錄,并對其中的文件、目錄和符號鏈接進行相應的處理。如何能夠獲取它們的列表,以及如何能夠確定它們究竟是什么?

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

開始之前

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

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

讀取目錄條目

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

dirent.h 函數(shù),opendir()、readdir() 和 closedir(),它們正是您所需要的。這些函數(shù)的使用與用來對文件進行操作的 open/read/close 的習慣用法非常相似,但有一點除外:對于每個目錄條目,readdir() 函數(shù)一次返回一個指向特殊結構(struct dirent 類型)的指針。通常,對目錄進行瀏覽類似于清單 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)問題時,opendir() 和 readdir() 函數(shù)都會返回 NULL,并且將設置全局變量 errno 的值,以指出所出現(xiàn)的錯誤。如果 readdir() 返回 NULL,并且 errno 為 0(有時也稱為 EOK 或 ENOERROR),則表示沒有其他的目錄條目。

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

請注意,readdir() 不是線程安全的,因為所返回的結構是存儲在函數(shù)庫中的一個靜態(tài)變量。大多數(shù)現(xiàn)代的 Unix 系統(tǒng)都具有線程安全的 readdir_r(),如果您正在編寫線程代碼,可以使用這個函數(shù)作為替代。

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

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

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

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

獲取文件信息

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

stat() 函數(shù)會將特定文件的相關信息填入 struct stat 結構中,如果您獲得的是文件描述符而不是文件名,那么作為替代,您可以使用 fstat() 函數(shù)。如果您想能夠檢測出符號鏈接,那么可以對文件名使用 lstat()。

與 readdir() 返回的 struct dirent 不同,struct stat 具有相當多的標準的、必需的成員:

st_mode——文件權限(用戶、其他用戶、組)和標志

st_ino——文件序列號

st_dev——文件設備號

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

st_uid——所有者用戶 ID

st_gid——所有者組 ID

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

st_atime——最后的訪問時間

st_mtime——最后的修改時間

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

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

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

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

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

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

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

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

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

關于符號鏈接的說明

通常,您并不關心符號鏈接。如果對符號鏈接調(diào)用 stat(),那么您將獲取該鏈接所指向的文件的相關信息。這和用戶的體驗是一致的,因為控制與該文件交互的是目標文件的權限,而不是符號鏈接本身。

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

將其組合在一起

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

這里所介紹的代碼將瀏覽命令行中指定的一個或多個目錄,并顯示在該目錄中找到的每個條目的相關信息。當它找到另一個目錄時,它會對該目錄進行同樣的處理。對于符號鏈接,將顯示其目標文件,并且還將顯示普通文件的大小。將忽略特殊文件。

如清單 2 所示,這個簡單的演示應用程序中包含了各種 Header 文件。程序的開始塊中包含了大多數(shù)程序中使用的標準部分,并且后面的四項是在該程序中使用 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ù)(開始于清單 3,結束于清單 6)讀取了指定的目錄,并顯示了每個條目的相關信息。opendir() 返回的 DIR 指針與 fopen() 返回的 FILE 指針類似,它是一個用于跟蹤目錄流的操作系統(tǒng)特定的對象,您應該忽略其具體內(nèi)容。

清單 3. 處理一個目錄

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;}

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

清單 4. 讀取一個目錄條目

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)得到了目錄的條目名稱,那么您需要構造一個更加完整的路徑(請參見清單 5),然后調(diào)用 lstat() 以獲取該條目的相關信息。因為符號鏈接需要特殊的處理,所以這里使用了 lstat() 函數(shù)。您可以使用 readlink() 函數(shù)找到其目標文件。

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

清單 5. 處理條目

(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)的底部,讀取另一個目錄條目并對其進行處理。如果您完成了對目錄條目的處理,那么關閉當前打開的目錄,并返回經(jīng)過處理的條目的數(shù)目。

清單 6. 讀取另一個條目

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

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

清單 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;}

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

結束語

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

標簽: Unix系統(tǒng)
主站蜘蛛池模板: 行星搅拌机,双行星搅拌机,动力混合机,无锡米克斯行星搅拌机生产厂家 | 微学堂-电动能源汽车评测_电动车性能分享网 | 氧化锆陶瓷_氧化锆陶瓷加工_氧化锆陶瓷生产厂家-康柏工业陶瓷有限公司 | 南京种植牙医院【官方挂号】_南京治疗种植牙医院那个好_南京看种植牙哪里好_南京茀莱堡口腔医院 尼龙PA610树脂,尼龙PA612树脂,尼龙PA1010树脂,透明尼龙-谷骐科技【官网】 | 恒温振荡混匀器-微孔板振荡器厂家-多管涡旋混匀器厂家-合肥艾本森(www.17world.net) | NM-02立式吸污机_ZHCS-02软轴刷_二合一吸刷软轴刷-厦门地坤科技有限公司 | 兰州牛肉面加盟,兰州牛肉拉面加盟-京穆兰牛肉面 | 恒温油槽-恒温水槽-低温恒温槽厂家-宁波科麦仪器有限公司 | 视觉检测设备_自动化检测设备_CCD视觉检测机_外观缺陷检测-瑞智光电 | 火锅底料批发-串串香技术培训[川禾川调官网] | 硬质合金模具_硬质合金非标定制_硬面加工「生产厂家」-西迪技术股份有限公司 | 全自动面膜机_面膜折叠机价格_面膜灌装机定制_高速折棉机厂家-深圳市益豪科技有限公司 | 砍排机-锯骨机-冻肉切丁机-熟肉切片机-预制菜生产线一站式服务厂商 - 广州市祥九瑞盈机械设备有限公司 | 冷藏车厂家|冷藏车价格|小型冷藏车|散装饲料车厂家|程力专用汽车股份有限公司销售十二分公司 | 网架支座@球铰支座@钢结构支座@成品支座厂家@万向滑动支座_桥兴工程橡胶有限公司 | 无锡网站建设_企业网站定制-网站制作公司-阿凡达网络 | 水篦子|雨篦子|镀锌格栅雨水篦子|不锈钢排水篦子|地下车库水箅子—安平县云航丝网制品厂 | 外贸网站建设-外贸网站设计制作开发公司-外贸独立站建设【企术】 | 外观设计_设备外观设计_外观设计公司_产品外观设计_机械设备外观设计_东莞工业设计公司-意品深蓝 | 电地暖-电采暖-发热膜-石墨烯电热膜品牌加盟-暖季地暖厂家 | 三效蒸发器_多效蒸发器价格_四效三效蒸发器厂家-青岛康景辉 | 噪声治理公司-噪音治理专业隔音降噪公司| 新型游乐设备,360大摆锤游乐设备「诚信厂家」-山东方鑫游乐设备 新能源汽车电池软连接,铜铝复合膜柔性连接,电力母排-容发智能科技(无锡)有限公司 | 期货软件-专业期货分析软件下载-云智赢 | 塑料脸盆批发,塑料盆生产厂家,临沂塑料广告盆,临沂家用塑料盆-临沂市永顺塑业 | 北京浩云律师事务所-企业法律顾问_破产清算等公司法律服务 | 超声波气象站_防爆气象站_空气质量监测站_负氧离子检测仪-风途物联网 | 裹包机|裹膜机|缠膜机|绕膜机-上海晏陵智能设备有限公司 | 排烟防火阀-消防排烟风机-正压送风口-厂家-价格-哪家好-德州鑫港旺通风设备有限公司 | 胶辊硫化罐_胶鞋硫化罐_硫化罐厂家-山东鑫泰鑫智能装备有限公司 意大利Frascold/富士豪压缩机_富士豪半封闭压缩机_富士豪活塞压缩机_富士豪螺杆压缩机 | 广州企亚 - 数码直喷、白墨印花、源头厂家、透气无手感方案服务商! | 金刚网,金刚网窗纱,不锈钢网,金刚网厂家- 河北萨邦丝网制品有限公司 | Q361F全焊接球阀,200X减压稳压阀,ZJHP气动单座调节阀-上海戎钛 | CTAB,表面活性剂1631溴型(十六烷基三甲基溴化铵)-上海升纬化工原料有限公司 | 液压升降平台_剪叉式液压/导轨式升降机_传菜机定做「宁波日腾升降机厂家」 | 胜为光纤光缆_光纤跳线_单模尾纤_光纤收发器_ODF光纤配线架厂家直销_北京睿创胜为科技有限公司 - 北京睿创胜为科技有限公司 | 产业规划_产业园区规划-产业投资选址及规划招商托管一体化服务商-中机院产业园区规划网 | 铝机箱_铝外壳加工_铝外壳厂家_CNC散热器加工-惠州市铂源五金制品有限公司 | 凝胶成像系统(wb成像系统)百科-上海嘉鹏| 工业机械三维动画制作 环保设备原理三维演示动画 自动化装配产线三维动画制作公司-南京燃动数字 聚合氯化铝_喷雾聚氯化铝_聚合氯化铝铁厂家_郑州亿升化工有限公司 | 东莞韩创-专业绝缘骨架|马达塑胶零件|塑胶电机配件|塑封电机骨架厂家 |