通過stat()讀取指定文件狀態, 然后通過宏測試struct stat的st_mode成員得到文件類型.
stat函數有3個版本, 它們的區別是stat參數需要一個文件路徑, fstat需要一個已打開文件描述符, lstat不跟隨符號鏈接(當文件是符號鏈接時, 獲得符號鏈接自身文件狀態, 而不是獲得其指向的文件狀態)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
struct stat定義
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
可以通過宏確定文件類型
宏 | 文件類型 |
---|---|
S_ISREG() | 普通文件 |
S_ISDIR() | 目錄文件 |
S_ISCHR() | 字符特殊文件 |
S_ISBLK() | 塊特殊文件 |
S_ISFIFO() | 管道或FIFO |
S_ISLNK() | 符號鏈接 |
S_ISSOCK() | 套接字 |
也可以通過宏確定IPC(進程間通信)對象類型
宏 | 文件類型 |
---|---|
S_TYPEISMQ() | 消息隊列 |
S_TYPEISSEM() | 信號量 |
S_TYPEISSHM() | 共享內存對象 |
文件類型宏測試實質是按位與運算, 我們也可以手動按位與運算. 以S_ISDIR為例, 在unistd.h中, 其定義:
#define S_ISDIR(mode) ((mode) & S_IFMT) == S_IFDIR)
示例: 創建2個文件, 分別是普通文件類型和目錄, 判斷並打印出文件類型
更詳細的示例 參見man 2 stat
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define FILE_NUM 2
void printFileType(char *path) {
struct stat stat_buf;
int ret = stat(path, &stat_buf);
if (ret < 0) {
perror("stat error");
return;
}
if (S_ISREG(stat_buf.st_mode)) {
printf("%s: general file\n", path);
}
else if(S_ISDIR(stat_buf.st_mode)) {
printf("%s: direcotry\n", path);
}
else {
printf("%s: other file type\n", path);
}
}
int main() {
char *filepaths[FILE_NUM] = {
"./file", "./dir"
};
int ret = -1;
for (int i = 0; i < FILE_NUM; ++i){
if (access(filepaths[i], O_RDONLY) < 0) {
ret = creat(filepaths[i], 0664);
if (ret < 0) {
perror("creat error");
exit(1);
}
}
}
for (int i = 0; i < FILE_NUM; ++i) {
printFileType(filepaths[i]);
}
return 0;
}
運行結果
$ touch file
$ mkdir dir
$ ./a.out
./file: general file
./dir: direcotry