本文轉載自實驗樓:文件I/O(二)
stat 的使用
Linux有個命令,ls -l,效果如下:
$ ls -l
-rw-rw-r-- 1 shiyanlou shiyanlou 978 Sep 19 02:13 hello.c
這個命令能顯示文件的類型、操作權限、硬鏈接數量、屬主、所屬組、大小、修改時間、文件名。它是怎么獲得這些信息,這一節我們將撥開迷霧。
stat 的基本使用
系統調用stat的作用是獲取文件的各個屬性。
需要包含的頭文件:
- <sys/types.h>
- <sys/stat.h>
- <unistd.h>
函數原型:
int stat(const char \* path, struct stat \* buf)
功能:查看文件或目錄屬性。將參數path所指的文件的屬性,復制到參數buf所指的結構中。
參數:
- path:要查看屬性的文件或目錄的全路徑名稱。
- buf:指向用于存放屬性的結構體。stat成功調用后,buf的各個字段將存放各個屬性。
- struct stat是系統頭文件中定義的結構體,定義如下:
struct stat {
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
blksize_t st_blksize;
blkcnt_t st_blocks;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
};
- st_ino:節點號
- st_mode:文件類型和文件訪問權限被編碼在該字段中
- st_nlink:硬連接數
- st_uid:屬主的用戶ID
- st_gid:所屬組的組ID
- st_rdev:設備文件的主、次設備號編碼在該字段中
- st_size:文件的大小
- st_mtime:文件最后被修改時間
返回值:成功返回0;失敗返回-1
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
struct stat buf;
if(argc != 2) {
printf("Usage: stat <pathname>");
exit(-1);
}
if(stat(argv[1], &buf) != 0) {
printf("stat error.");
exit(-1);
}
printf("#i-node: %ld\n", buf.st_ino);
printf("#link: %d\n", buf.st_nlink);
printf("UID: %d\n", buf.st_uid);
printf("GID: %d\n", buf.st_gid);
printf("Size %ld\n", buf.st_size);
exit(0);
}
文件類型的判定
上一小節中struct stat中有個字段為st_mode,可用來獲取文件類型和文件訪問權限,我們將陸續學到從該字段解碼我們需要的文件信息
。st_mode中文件類型宏定義:
宏定義 | 文件類型 |
---|---|
S_ISREG() | 普通文件 |
S_ISDIR() | 目錄文件 |
S_ISCHR() | 字符設備文件 |
S_ISBLK() | 塊設備文件 |
S_ISFIFO() | 有名管道文件 |
S_ISLNK() | 軟連接(符號鏈接)文件 |
S_ISSOCK() | 套接字文件 |
我們修改上面的例子:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv)
{
struct stat buf;
char * file_mode;
if(argc != 2) {
printf("Usage: stat <pathname>\n");
exit(-1);
}
if(stat(argv[1], &buf) != 0) {
printf("stat error.\n");
exit(-1);
}
if (S_ISREG(buf.st_mode))
file_mode = "-";
else if (S_ISDIR(buf.st_mode))
file_mode = "d";
else if (S_ISCHR(buf.st_mode))
file_mode = "c";
else if(S_ISBLK(buf.st_mode))
file_mode = "b";
printf("#i-node: %ld\n", buf.st_ino);
printf("#link: %d\n", buf.st_nlink);
printf("UID: %d\n", buf.st_uid);
printf("GID: %d\n", buf.st_gid);
printf("Size %ld\n", buf.st_size);
printf("mode: %s\n", file_mode);
exit(0);
}
文件權限的判定
文件類型與許可設定被一起編碼在st_mode字段中,同上面一樣,我們也需要一組由系統提供的宏來完成解碼。
宏定義 | 文件類型 |
---|---|
S_ISUID | 執行時,設置用戶ID |
S_ISGID | 執行時,設置組ID |
S_ISVTX | 保存正文 |
S_IRWXU | 擁有者的讀、寫和執行權限 |
S_IRUSR | 擁有者的讀權限 |
S_IWUSR | 擁有者的寫權限 |
S_IXUSR | 擁有者的執行權限 |
S_IRWXG | 用戶組的讀、寫和執行權限 |
S_IRGRP | 用戶組的讀權限 |
S_IWGRP | 用戶組的寫權限 |
S_IRWXO | 其它讀、寫、執行權限 |
S_IROTH | 其它讀權限 |
S_IWOTH | 其它寫權限 |
S_IXOTH | 其它執行權限 |
目錄操作
當目標是目錄而不是文件的時候,ls -l的結果會顯示目錄下所有子條目的信息,怎么去遍歷整個目錄呢?
打開目錄
需要包含的頭文件:
- <sys/types.h>
- <dirent.h>
函數原型:
DIR * opendir(const char * name)
功能:opendir()用來打開參數name指定的目錄,并返回DIR *形態的目錄流
返回值:成功返回目錄流;失敗返回NULL
讀取目錄
函數原型:
struct dirent * readdir(DIR * dir)
功能:readdir()返回參數dir目錄流的下一個子條目(子目錄或子文件)
返回值: 成功返回結構體指向的指針,錯誤或以讀完目錄,返回NULL
函數執行成功返回的結構體原型如下:
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};
其中 d_name字段,是存放子條目的名稱
關閉目錄
函數原型:
int closedir(DIR * dir)
功能:closedir()關閉dir所指的目錄流
返回值:成功返回0;失敗返回-1,錯誤原因在errno中
我們來學習一個綜合的例子吧:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char *argv[])
{
DIR *dp;
struct dirent *entp;
if (argc != 2) {
printf("usage: showdir dirname\n");
exit(0);
}
if ((dp = opendir(argv[1])) == NULL) {
perror("opendir");
exit(-1);
}
while ((entp = readdir(dp)) != NULL)
printf("%s\n", entp->d_name);
closedir(dp);
return 0;
}