本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/。
UNIX系統的大多數文件是普通文件或目錄,但是也有另外一些文件類型。文件類型包括如下幾種:
(1)普通文件(regular file)。這是最常見的文件類型,這種文件包含了某種形式的數據。至于這種數據是文本還是二進制數據對于UNIX內核而言并無區別。對普通文件的解釋由處理該文件的應用程序進行。
一個值得注意的例外是二進制可執行文件。為了執行程序,內核必須理解其格式。所有二進制可執行文件都遵循一種格式,這種格式使內核能夠確定程序文本和數據的加載位置。
(2)目錄文件(directory file)。這種文件包含了其他文件的名字以及指向這些文件有關信息的指針。對一個目錄文件具有讀權限的任一進程都可以讀該目錄的內容,但只有內核可以直接寫目錄文件。進程必須使用特定的函數才能更改目錄。
(3)塊特殊文件(block special file)。這種文件類型提供對設備(例如磁盤)帶緩沖的訪問,每次訪問以固定長度為單位進行。
(4)字符特殊文件(character special file)。這種文件類型提供對設備不帶緩沖的訪問,每次訪問長度可變。系統中的所有設備要么是字符特殊文件,要么是塊特殊文件。
(5)FIFO。這種類型文件用于進程間通信,有時也將其稱為命名管道(named pipe)。
(6)套接字(socket)。這種文件類型用于進程間的網絡通信。套接字也可用于在一臺宿主機上進程之間的非網絡通信。
(7)符號鏈接(symbolic link)。這種文件類型指向另一個文件。
文件類型信息包含在stat結構的st_mode成員中??梢杂帽?-1中的宏確定文件類型。這些宏的參數都是stat結構中的st_mode成員。
表4-1 <sys/stat.h>中的文件類型宏
宏 | 文件類型 |
S_ISREG() | 普通文件 |
S_ISDIR() | 目錄文件 |
S_ISCHR() | 字符特殊文件 |
S_ISBLK() | 塊特殊文件 |
S_ISFIFO() | 管道或FIFO |
S_ISLNK() | 符號鏈接 |
S_ISSOCK() | 套接字 |
POSIX.1允許實現將進程間通信(IPC)對象(例如,消息隊列和信號量等)表示為文件。表4-2的宏用來確定IPC對象的類型。這些宏與表4-1中的不同,它們的參數并非st_mode而是指向stat結構的指針。
表4-2 <sys/stat.h>中的IPC類型宏
宏 | 對象的類型 |
S_TYPEISMQ() | 消息隊列 |
S_TYPEISSEM() | 信號量 |
S_TYPEISSHM() | 共享存儲對象 |
注:linux系統并不將這些對象表示為文件。
程序清單4-1 對每個命令行參數打印文件類型
[root@localhost apue]# cat PRog4-1.c #include "apue.h"int main(int argc, char *argv[]){ int i; struct stat buf; char *ptr; for(i=0; i<argc; i++) { printf("%s: ", argv[i]); if(lstat(argv[i], &buf) < 0) { err_ret("lstat error"); continue; } if(S_ISREG(buf.st_mode)) ptr = "regular"; else if(S_ISDIR(buf.st_mode)) ptr = "directory"; else if(S_ISCHR(buf.st_mode)) ptr = "character special"; else if(S_ISBLK(buf.st_mode)) ptr = "block special"; else if(S_ISFIFO(buf.st_mode)) ptr = "fifo"; else if(S_ISLNK(buf.st_mode)) ptr = "symbolic link"; else if(S_ISSOCK(buf.st_mode)) ptr = "socket"; else ptr = "** unknown mode **"; printf("%s/n", ptr); } exit(0);}
編譯后運行該程序:
[root@localhost apue]# ./prog4-1 /etc/passwd /etc /dev/initctl /dev/log /dev/tty /dev/fd0 /dev/cdrom./prog4-1: regular/etc/passwd: regular/etc: directory/dev/initctl: fifo/dev/log: socket/dev/tty: character special/dev/fd0: block special/dev/cdrom: symbolic link
我們特地使用了lstat函數而不是stat函數以便檢測符號鏈接。如若使用了stat函數,則不會觀察到符號鏈接。
為了在Linux系統上編譯該程序,必須定義_GUN_SOURCE,這樣就能包括S_ISSOCK宏的定義。(我使用的是2.6.18內核Linux,編譯上述程序時,并沒有自己定義_GUN_SOURCE,編譯通過且運行成功。)
早期的UNIX系統版本并不提供S_ISxxx宏,于是就需要將st_mode與屏蔽字S_FIMT進行邏輯“與”運算,然后與名為S_IFxxx的常量相比較。大多數系統在文件<sys/stat.h>中定義了此屏蔽字和相關的常量。如若查看此文件,則可找到S_ISDIR宏定義為:
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
新聞熱點
疑難解答