lienhua34
2014-09-01
1 文件類型
我們平時最常接觸的文件類型有普通文件(regular file)和目錄(di-rectory file),但是 UNIX 系統提供了多種文件類型:
(1) 普通文件(regular file)
這種文件包含了某種形式的數據,這些數據無論是文件還是二進制對於 UNIX 內核而言都是一樣的。對普通文件內容的解釋有處理該文件的應用程序進行。
(2) 目錄文件(directory file)
目錄文件包含了其他文件的名字以及指向與這些文件有關信息的指針。對一個目錄文件具有讀權限的任一進程都可以讀取該目錄的內容,但是只有內核才能直接寫目錄文件。
(3) 塊特殊文件(block special file)
這種文件類型提供對設備帶緩沖的訪問,每次訪問以固定長度為單位進行。
(4) 字符特殊文件(character special file)
這種文件類型提供對設備不帶緩沖的訪問,每次訪問長度可變。系統中的所有設備要么是字符特殊文件,要么是塊特殊文件。
(5) FIFO
這種類型文件用於進程間通信。也稱為命名管道(namedpipe)。
(6) 套接字(socket)
這種文件類型用於進程間的網絡通信。
(7) 符號鏈接(symbolic link)
這種文件類型指向另一個文件。
我們如何判斷一個文件的文件類型呢?我們可以先通過stat函數獲取文件的屬性信息,然后從其屬性信息中判斷該文件的文件類型。
2 獲取文件屬性信息的stat函數
UNIX系統提供了三個 stat 函數以獲取文件的屬性信息,包括文件類型、所有者、大小和修改時間等。
#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);
三個函數返回值:若成功則返回0,若出錯則返回-1.
stat 函數獲取與命名文件有關的信息結構。fstat 函數獲取已在文件描述符filedes 上打開的文件的有關信息。lstat 函數類似於 stat 函數,但是當命名的文件是一個符號鏈接時,lstat 返回該符號鏈接的有關信息,而不是由該符號鏈接引用文件的信息。
第二個參數 buf 是指針,指向一個 struct stat 結構。這些函數填寫由buf 指向的結構。struct stat 結構的基本形式如下:
struct stat { mode_t st_mode; /* file type & mode (permissions) */ ino_t st_ino; /* i-node number (serial number) */ dev_t st_dev; /* device number (file system) */ dev_t st_rdev; /* device number for specail files */ nlink_t st_nlink; /* number of links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* size in bytes, for regular files */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last file status change */ blksize_t st_blksize; /* best I/O block size */ blkcnt_t st_blocks; /* number of disk blocks allocate */ }
3 判斷文件類型
文件類型信息包含在 stat 結構的st_mode 成員中。可以使用下表 1 中的宏來確定文件類型。這些宏的參數都是 stat 結構的st_mode 成員。
宏 | 文件類型 |
S_ISREG() | 普通文件 |
S_ISDIR() | 目錄文件 |
S_ISCHR() | 字符特殊文件 |
S_ISBLK() | 塊特殊文件 |
S_ISFIFO() | 管道或 FIFO |
S_ISLNK() | 符號鏈接 |
S_ISSOCK() | 套接字 |
下面程序取其命令行參數,然后針對每個命令行參數打印其文件類型。
#include <stdlib.h> #include <stdio.h> #include <sys/stat.h> #include <errno.h> #include <string.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) { printf("lstat error: %s\n", strerror(errno)); 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 = "** nuknown mode **"; } printf("%s\n", ptr); } exit(0); }
編譯該程序,生成文件 filetype,然后運行 filetype 文件,
lienhua34:demo$ gcc -o filetype filetype.c lienhua34:demo$ ./filetype /etc/passwd /etc /dev/initctl /dev/log /dev/tty ./filetype: regular /etc/passwd: regular /etc: directory /dev/initctl: lstat error: No such file or directory /dev/log: socket /dev/tty: character special
(done)