Linux 系统调用 stat 完全用例
stat 和 fstat 的主要区别在于获取文件属性的方式:
- stat 通过 文件名(路径) 直接获取文件属性,无需预先打开文件,适用于仅需查询属性而不操作文件内容的场景。
- fstat 通过 文件描述符(fd) 获取属性,要求文件必须已通过 open 等函数打开。其优势在于直接从内存读取动态文件的属性,效率更高,适合已打开文件的情况。
选择建议:
• 若仅需检查文件属性且文件未打开,使用 stat 避免额外开销;
• 若文件已打开(如正在读写),优先用 fstat 减少磁盘访问。
两者的返回信息均存储在 struct stat 结构体中,包含文件类型、权限、时间戳等元数据。
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>// 打印权限位
void print_permissions(mode_t mode) {printf( (S_ISDIR(mode)) ? "d" : "-");printf( (mode & S_IRUSR) ? "r" : "-");printf( (mode & S_IWUSR) ? "w" : "-");printf( (mode & S_IXUSR) ? "x" : "-");printf( (mode & S_IRGRP) ? "r" : "-");printf( (mode & S_IWGRP) ? "w" : "-");printf( (mode & S_IXGRP) ? "x" : "-");printf( (mode & S_IROTH) ? "r" : "-");printf( (mode & S_IWOTH) ? "w" : "-");printf( (mode & S_IXOTH) ? "x" : "-");
}// 打印文件类型
const char* file_type(mode_t mode) {if (S_ISREG(mode)) return "普通文件";if (S_ISDIR(mode)) return "目录";if (S_ISCHR(mode)) return "字符设备";if (S_ISBLK(mode)) return "块设备";if (S_ISFIFO(mode)) return "FIFO/管道";if (S_ISLNK(mode)) return "符号链接";if (S_ISSOCK(mode)) return "套接字";return "未知类型";
}int main(int argc, char *argv[]) {if (argc != 2) {fprintf(stderr, "用法: %s <文件路径>\n", argv[0]);return EXIT_FAILURE;}const char *filepath = argv[1];struct stat st;// 调用 stat 获取文件信息if (stat(filepath, &st) == -1) {fprintf(stderr, "stat 失败: %s\n", strerror(errno));return EXIT_FAILURE;}printf("文件: %s\n", filepath);printf("文件类型: %s\n", file_type(st.st_mode));printf("权限: ");print_permissions(st.st_mode);printf("\n");printf("节点号: %lu\n", (unsigned long)st.st_ino);printf("设备号: %lu\n", (unsigned long)st.st_dev);printf("硬链接数: %lu\n", (unsigned long)st.st_nlink);printf("用户ID: %u", st.st_uid);struct passwd *pw = getpwuid(st.st_uid);if (pw) printf(" (%s)", pw->pw_name);printf("\n");printf("组ID: %u", st.st_gid);struct group *gr = getgrgid(st.st_gid);if (gr) printf(" (%s)", gr->gr_name);printf("\n");printf("文件大小: %lld 字节\n", (long long)st.st_size);printf("块大小: %lld 字节\n", (long long)st.st_blksize);printf("占用块数: %lld 块\n", (long long)st.st_blocks);char timebuf[64];struct tm *tm_info;tm_info = localtime(&st.st_atime);strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_info);printf("最后访问时间: %s\n", timebuf);tm_info = localtime(&st.st_mtime);strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_info);printf("最后修改时间: %s\n", timebuf);tm_info = localtime(&st.st_ctime);strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_info);printf("状态改变时间: %s\n", timebuf);return EXIT_SUCCESS;
}