- Linux程序設(shè)計(第4版)
- (英)Neil Matthew Richard Stones
- 1854字
- 2021-04-09 20:04:45
3.8 掃描目錄
Linux系統(tǒng)上一個常見問題就是掃描目錄,也就是確定一個特定目錄下存放的文件。在shell程序設(shè)計中,這很容易做到——只需讓shell做一次表達式的通配符擴展。在過去,UNIX操作系統(tǒng)的各種變體都允許用戶通過編程訪問底層文件系統(tǒng)結(jié)構(gòu)。你仍然可以把目錄當作一個普通文件那樣打開,并直接讀取目錄數(shù)據(jù)項,但不同的文件系統(tǒng)結(jié)構(gòu)及其實現(xiàn)已經(jīng)使這種方法沒什么可移植性了。現(xiàn)在,一整套標準的庫函數(shù)已經(jīng)被開發(fā)出來,使得目錄的掃描工作變得簡單多了。
與目錄操作有關(guān)的函數(shù)在dirent.h頭文件中聲明。它們使用一個名為DIR的結(jié)構(gòu)作為目錄操作的基礎(chǔ)。被稱為目錄流的指向這個結(jié)構(gòu)的指針(DIR *)被用來完成各種目錄操作,其使用方法與用來操作普通文件的文件流(FILE *)非常相似。目錄數(shù)據(jù)項本身則在dirent結(jié)構(gòu)中返回,該結(jié)構(gòu)也是在dirent.h頭文件里聲明的,這是因為用戶不應(yīng)直接改動DIR結(jié)構(gòu)中的數(shù)據(jù)字段。
我們將介紹下面這幾個函數(shù):
? opendir
? readdir
? telldir
? seekdir
? closedir
3.8.1 opendir函數(shù)
opendir函數(shù)的作用是打開一個目錄并建立一個目錄流。如果成功,它返回一個指向DIR結(jié)構(gòu)的指針,該指針用于讀取目錄數(shù)據(jù)項。

opendir在失敗時返回一個空指針。注意,目錄流使用一個底層文件描述符來訪問目錄本身,所以如果打開的文件過多,opendir可能會失敗。
3.8.2 readdir函數(shù)
readdir函數(shù)返回一個指針,該指針指向的結(jié)構(gòu)里保存著目錄流dirp中下一個目錄項的有關(guān)資料。后續(xù)的readdir調(diào)用將返回后續(xù)的目錄項。如果發(fā)生錯誤或者到達目錄尾,readdir將返回NULL。POSIX兼容的系統(tǒng)在到達目錄尾時會返回NULL,但并不改變errno的值,只有在發(fā)生錯誤時才會設(shè)置errno。

注意,如果在readdir函數(shù)掃描目錄的同時還有其他進程在該目錄里創(chuàng)建或刪除文件,readdir將不保證能夠列出該目錄里的所有文件(和子目錄)。
dirent結(jié)構(gòu)中包含的目錄項內(nèi)容包括以下部分。
? ino_t d_ino:文件的inode節(jié)點號。
? char d_name[]:文件的名字。
要想進一步了解目錄中某個文件,你需要使用在本章前面介紹過的stat調(diào)用。
3.8.3 telldir函數(shù)
telldir函數(shù)的返回值記錄著一個目錄流里的當前位置。你可以在隨后的seekdir調(diào)用中利用這個值來重置目錄掃描到當前位置。

3.8.4 seekdir函數(shù)
seekdir函數(shù)的作用是設(shè)置目錄流dirp的目錄項指針。loc的值用來設(shè)置指針位置,它應(yīng)該通過前一個telldir調(diào)用獲得。

3.8.5 closedir函數(shù)
closedir函數(shù)關(guān)閉一個目錄流并釋放與之關(guān)聯(lián)的資源。它在執(zhí)行成功時返回0,發(fā)生錯誤時返回-1。

在下面的printdir.c程序中,你將把許多文件處理函數(shù)集中在一起以實現(xiàn)一個簡單的目錄列表功能。目錄中的每個文件單獨列在一行上。每個子目錄會在它的名字后面加上一個斜線字符/,子目錄中的文件在縮進四個空格后依次排列。
程序會逐個切換到每個下級子目錄里,這樣使它找到的文件都有一個可用的名字。也就是說,它們都可以被直接傳遞給opendir函數(shù)。如果目錄的嵌套層次太深,程序執(zhí)行就會失敗,這是因為對允許打開的目錄流數(shù)目是有限制的。
我們當然可以采取一個更通用的做法,讓程序能夠通過一個命令行參數(shù)來指定起點(從哪個目錄開始)。請查閱有關(guān)工具程序(如ls和find)的Linux源代碼來找到實現(xiàn)更通用程序的方法。
實驗 一個目錄掃描程序
(1)程序的開始是一些必要的頭文件。接下來是printdir函數(shù),它的作用是輸出當前目錄的內(nèi)容。它將遞歸遍歷各級子目錄,使用depth參數(shù)來控制縮排。

(2)下面是main函數(shù):

這個程序掃描home目錄并產(chǎn)生如下所示的輸出(經(jīng)過簡化)。如果想掃描其他用戶的目錄,你可能需要超級用戶的權(quán)限。

實驗解析
絕大部分操作都是在printdir函數(shù)里完成的。在用opendir函數(shù)檢查完指定目錄是否存在后,printdir調(diào)用chdir進入指定目錄。如果readdir函數(shù)返回的數(shù)據(jù)項不為空,程序就檢查該數(shù)據(jù)項是否是一個目錄。如果不是,程序就根據(jù)depth的值縮進打印該文件數(shù)據(jù)項的內(nèi)容。
如果該數(shù)據(jù)項是一個目錄,你就需要對它進行遞歸遍歷。在跳過.和..數(shù)據(jù)項(它們分別代表當前目錄和上一級目錄)后,printdir函數(shù)調(diào)用自己并再次進入一個同樣的處理過程。那它又是如何退出這些循環(huán)的呢?一旦while循環(huán)完成,chdir("..")調(diào)用將把它帶回到目錄樹的上一級,從而可以繼續(xù)進行上級目錄的遍歷。調(diào)用closedir(dp)關(guān)閉目錄是為了確保打開的目錄流數(shù)目不超出其需要。
作為對第4章所介紹的Linux環(huán)境的一個簡短嘗試,讓我們來看一個能夠使這個程序更具通用性的方法。這個程序的功能受限是因為它只能對目錄/home進行操作。如果我們按下面的方法對main函數(shù)進行修改,就能把它變成一個更有用的目錄瀏覽器:

我們修改了3條語句,增加了5條語句,它現(xiàn)在是一個通用的工具程序了。它多了一個可選的目錄名參數(shù),其默認值是當前目錄。你可以通過下面的命令運行它:

輸出結(jié)果將分頁顯示,用戶可以通過翻頁查看其輸出。可以說,用戶現(xiàn)在有了一個非常方便、通用的目錄樹瀏覽器。你不必花費過多精力就可以為這個程序再增加空間占用統(tǒng)計、遍歷深度限制等其他功能。
- INSTANT FreeMarker Starter
- 零基礎(chǔ)入門學習Python(第2版)
- Unity 2017 Mobile Game Development
- Mastering React
- Creating Data Stories with Tableau Public
- Everyday Data Structures
- 代碼閱讀
- 交互式程序設(shè)計(第2版)
- Web程序設(shè)計:ASP.NET(第2版)
- Learning Grunt
- Android嵌入式系統(tǒng)程序開發(fā)(基于Cortex-A8)
- Java編程指南:語法基礎(chǔ)、面向?qū)ο蟆⒑瘮?shù)式編程與項目實戰(zhàn)
- Managing Windows Servers with Chef
- Scala編程(第4版)
- Practical Linux Security Cookbook