本章在第三章的基礎上描述文件的屬性,如大小、建立時間等。html
本章最後介紹對目錄進行操做的各個函數。網絡
1、stat()、fstat()、fstatat()和lstat()socket
stat系列函數用於返回文件的屬性信息,如文件類型、大小、全部者、訪問修改時間等。函數聲明以下:函數
1 /* 文件屬性查看函數 */ 2 #include <sys/stat.h> 3 4 int stat(const char *pathname, struct stat *buf); 5 int fstat(int fd, struct stat *buf); 6 int lstat(const char *pathname, struct stat *buf); 7 int fstatat(int fd, const char *pathname, struct stat *buf, int flags); 8 9 /* 例子 */ 10 struct stat st; 11 fstat(fd, &st); 12 char *buf; 13 14 if (S_ISREG(st.st_mode)) 15 buf = "regular"; /* 普通文件 */ 16 else if (S_ISDIR(st.st_mode)) 17 buf = "directory"; /* 目錄 */ 18 else if (S_ISCHR(st.st_mode)) 19 buf = "character special"; /* 字符文件 */ 20 else if (S_ISBLK(st.st_mode)) 21 buf = "block special"; /* 塊文件 */ 22 else if (S_ISFIFO(st.st_mode)) 23 buf = "fifo"; /* 管道文件 */ 24 /* 25 else if (S_ISLINK(st.st_mode)) 26 buf = "link"; /* 連接文件,使用fstat()沒法識別 */ 27 */ 28 else if (S_ISSOCK(st.st_mode)) 29 buf = "socket"; /* 網絡套接字 */ 30 else 31 buf = "unknow mode"; 32 33 printf("%s\n", buf);
函數參數以及返回值:測試
pathname:文件路徑名ui
buf:返回的stat結構體url
fd:文件打開函數返回的文件描述符spa
flags:標識符.net
返回值:成功返回0;出錯返回-1。指針
上面函數返回的stat結構體各個實現可能存在差別,但它們都至少具有下列的信息:
1 struct stat { 2 mode_t st_mode; // 文件類型和訪問權限 3 ino_t st_ino; // 指向數據塊的節點的編號 4 dev_t st_dev; // 設備號 5 dev_t st_rdev; 6 nlink_t st_nlink; // 硬連接數 7 uid_t st_uid; // 用戶ID 8 gid_t st_gid; // 用戶組ID 9 off_t st_size; 10 struct timespec st_atim; // 數據訪問時間 11 struct timespec st_mtim; // 數據修改時間 12 struct timespec st_ctim; // 屬性修改時間 13 blksize_t st_blksize; // 最好的IO塊大小 14 blkcnt_t st_blocks; 15 };
2、文件類型
UNIX系統中的文件大多數是普通文件和目錄,但也存在其餘類型的文件,其分類以下:
普通文件(regular file):包含數據的常規文件,數據能夠是文本類型的,也能夠是二進制的。
目錄文件(directory file):它是一個目錄,保存目錄相關的信息。
塊設備文件(block special file):這種文件提供對硬件(如磁盤)帶緩衝的訪問。
字符設備文件(regular file):這種文件提供對硬件(如磁盤)不帶緩衝的訪問。
FIFO:這種文件用於進程間通訊。
套接字文件(regular file):這種文件用於網絡間通訊。
符號鏈接(regular file):相似Windows系統的快捷方式,指向另一個文件。
以上文件類型的信息存儲在前面說明的stat結構體中st_mode成員中的。正如我所給出的上面的例子,st_mode成員的讀取是利用系統提供的宏函數進行的。在此我總結如下上文例子中的宏函數:
S_ISREG() /* 普通文件 */ S_ISDIR() /* 目錄 */ S_ISCHR() /* 字符文件 */ S_ISBLK() /* 塊文件 */ S_ISFIFO() /* 管道文件 */ S_ISLINK() /* 連接文件 */ S_ISSOCK() /* 網絡套接字 */
3、文件訪問權限
stat結構體中st_mode成員還包含有文件的訪問權限,訪問權限曾在第三章第二節有簡單的演示。
爲了打開任意類型的一個文件,則須要對該文件所在的父級以及父級的父級等目錄具備執行權限。刪除一個文件不須要對該文件有任何權限,只須要對被刪除文件的父級目錄具備寫和執行權限便可。
進程每次打開、建立或刪除一個文件時,內核就對該文件進行訪問權限測試,一般的步驟是:
1. 先判斷進程是不是超級用戶,即ID是否爲0,是則容許訪問,不然執行第二步;
2. 再判斷進程的有效用戶ID是否等於文件的全部者ID,若是是而且被訪問文件設定了適當的讀寫權限,則容許訪問;不然執行第三步;
3. 而後判斷進程有效組ID或者附加組ID是否等於文件的組ID,若是是而且被訪問文件設定了適當的讀寫權限,則容許訪問;不然執行第四步;
4. 最後查看文件的其餘用戶是否有適當權限訪問文件,有則容許,不然判斷結束、訪問失敗。
4、access()和faccessat()
access()和faccessat()函數可用於判斷當前用戶是否具備訪問某個文件的權限。函數聲明以下:
1 /* 權限檢測函數 */ 2 #include <unistd.h> 3 4 int access(const char *pathname, int mode); 5 int faccessat(int fd, const char *pathname, int mode, int flags); 6 7 /* 例子 */ 8 if (access("a.txt", R_OK) == 0) /* 是否有讀權限 */ 9 printf("a.txt read ok\n"); 10 if (access("a.txt", W_OK) == 0) /* 是否有寫權限 */ 11 printf("a.txt write ok\n"); 12 if (access("a.txt", X_OK) == 0) /* 是否有執行權限 */ 13 printf("a.txt execute ok\n");
函數參數以及返回值:
pathname:文件路徑名
mode:模式,包含有R_OK、W_OK、X_OK和F_OK
flags:標識符
返回值:有權限返回0
5、文件操做其餘函數
權限屏蔽函數umask(),用於設置建立新文件時的權限屏蔽字,對於修改文件權限時權限屏蔽字沒有效果,函數聲明以下:
#include <sys/stat.h> mode_t umask(mode_t mask); /* 例子 */ mode_t old = umask(0222); /* 若是原來的權限是0777,那麼最終的結果是077 - 0222 = 0555,old返回原來的權限 */ umask(old); /* 恢復權限 */
chmod()、fchmod()和fchmodat()這三個函數用於更改文件的訪問權限。函數聲明以下:
1 #include <sys/stat.h> 2 3 int chmod(const char *file, mode_t mode); 4 int fchmod(int fd, mode_t mode); 5 int fchmodat(int fd, const char *file, mode_t mode, int flag); 6 7 /* 例子 */ 8 fchmod(fd, 0666); /* 更改權限爲0666 */
權限改變成功則返回0,失敗返回-1。
6、目錄相關函數
1 #include <dirent.h> 2 3 /* 打開一個目錄 */ 4 DIR *opendir(const char *name); // 成功返回指針,失敗返回NULL 5 DIR *fdopendir(int fd); // 成功返回指針,失敗返回NULL 6 7 /* 讀取目錄中的內容,如文件、子目錄 */ 8 struct dirent *readdir(DIR *dirp); // 成功返回指針,失敗返回NULL 9 10 /* 讓目前的讀取位置還原到開頭的讀取位置 */ 11 void rewinddir(DIR *dirp); 12 13 /* 設置相對於開頭偏移值爲pos的讀取位置 */ 14 void seekdir(DIR *dirp, long int pos); 15 16 /* 關閉目錄 */ 17 int closedir(DIR *dirp); // 成功時返回0,失敗返回-1 18 19 /* 例子 */ 20 DIR* dir = opendir("../"); 21 struct dirent* ent; 22 while(ent=readdir(dir)) // 1 讀, 2 =,3 判斷ent是否爲0 23 { 24 printf("%d, %s\n", ent->d_type, ent->d_name); 25 } // d_tpye == 4 的是目錄 26 closedir(dir);
讀某個目錄內容(子項)的步驟:
1. opendir()返回目錄指針
2. 循環調用readdir(),逐一讀取每一個子項
3. closedir()關閉目錄,這步也能夠省略
若是咱們想要查看該目錄以及其子目錄的全部文件呢?
程序代碼以下:
1 #include <stdio.h> 2 #include <dirent.h> 3 #include <string.h> 4 5 static void read_all_dir(char *path) 6 { 7 DIR *dir = opendir(path); 8 if (NULL == dir) 9 return; 10 11 struct dirent *ent; 12 13 while(ent = readdir(dir)) { 14 if ((0 == strcmp(ent->d_name, ".")) || 15 (0 == strcmp(ent->d_name, ".."))) 16 continue; 17 if (8 == ent->d_type) { 18 printf("%s\n", ent->d_name); 19 } 20 else if (4 == ent->d_type) { 21 char buf[100] = { /* NULL */ }; 22 sprintf(buf, "%s/%s", path, ent->d_name); 23 printf("[%s]\n", ent->d_name); 24 read_all_dir(buf); 25 } 26 } 27 closedir(dir); 28 } 29 30 int main() 31 { 32 read_all_dir("../"); 33 34 return 0; 35 }
下一章 第五章:標準I/O庫