当前位置: 首页 > news >正文

`stat` 系统调用详解

stat 是 Unix/Linux 系统中用于获取文件状态信息的核心系统调用。它能够提供关于文件的元数据,而无需打开文件本身。

1. 函数的概念与用途

stat 函数用于获取指定路径名对应文件的信息,包括文件大小、权限、所有者、时间戳等元数据。这些信息存储在 struct stat 结构中。

主要用途:

  • 检查文件是否存在及其类型(普通文件、目录、符号链接等)
  • 获取文件大小、权限和所有权信息
  • 查看文件的访问、修改和状态变更时间
  • 实现类似 ls -l 命令的功能
  • 在文件操作前验证文件属性

2. 函数的声明与出处

stat 函数及其相关变体定义在 <sys/stat.h> 头文件中,是 POSIX 标准的一部分。

#include <sys/stat.h>int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);

三种变体的区别:

  • stat(): 获取路径名指向的文件信息(会跟随符号链接)
  • lstat(): 类似 stat(),但不跟随符号链接(获取链接本身的信息)
  • fstat(): 通过文件描述符获取已打开文件的信息

3. 返回值的含义与取值范围

  • 成功时:返回 0
  • 失败时:返回 -1,并设置 errno 来指示错误原因

常见错误码 (errno):

  • ENOENT: 路径名的一部分不存在
  • EACCES: 对路径名的某部分无搜索权限
  • ENOTDIR: 路径名的某部分不是目录
  • ELOOP: 解析路径名时遇到太多符号链接
  • EFAULT: 错误的地址
  • ENAMETOOLONG: 路径名太长

4. 参数的含义与取值范围

  1. const char *pathname (对于 statlstat)

    • 含义:要查询的文件路径
    • 取值范围:任何有效的文件系统路径(绝对或相对路径)
  2. int fd (对于 fstat)

    • 含义:已打开文件的文件描述符
    • 取值范围:有效的文件描述符(通常由 open() 返回)
  3. struct stat *statbuf (所有变体)

    • 含义:指向 struct stat 的指针,用于存储获取到的文件信息
    • 取值范围:必须指向有效的内存位置,大小至少为 sizeof(struct stat)

5. struct stat 结构体详解

struct stat 包含丰富的文件元数据,其具体字段可能因系统而异,但通常包括:

struct stat {dev_t     st_dev;         /* 文件所在设备的 ID */ino_t     st_ino;         /* Inode 号 */mode_t    st_mode;        /* 文件类型和模式 */nlink_t   st_nlink;       /* 硬链接数 */uid_t     st_uid;         /* 所有者的用户 ID */gid_t     st_gid;         /* 所有者的组 ID */dev_t     st_rdev;        /* 设备 ID(如果是特殊文件) */off_t     st_size;        /* 总大小,字节为单位 */blksize_t st_blksize;     /* 文件系统 I/O 的块大小 */blkcnt_t  st_blocks;      /* 分配的 512B 块数 *//* 时间戳(具体精度和字段可能因系统而异) */time_t    st_atime;       /* 最后访问时间 */time_t    st_mtime;       /* 最后修改时间 */time_t    st_ctime;       /* 最后状态变更时间 */
};

6. 函数使用案例

下面是一个完整的示例,展示如何使用 stat 获取文件信息:

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <string.h>void print_file_type(mode_t mode) {if (S_ISREG(mode)) printf("普通文件");else if (S_ISDIR(mode)) printf("目录");else if (S_ISCHR(mode)) printf("字符设备");else if (S_ISBLK(mode)) printf("块设备");else if (S_ISFIFO(mode)) printf("FIFO/命名管道");else if (S_ISLNK(mode)) printf("符号链接");else if (S_ISSOCK(mode)) printf("套接字");else printf("未知类型");
}void print_permissions(mode_t mode) {printf("%c%c%c%c%c%c%c%c%c",(mode & S_IRUSR) ? 'r' : '-',(mode & S_IWUSR) ? 'w' : '-',(mode & S_IXUSR) ? 'x' : '-',(mode & S_IRGRP) ? 'r' : '-',(mode & S_IWGRP) ? 'w' : '-',(mode & S_IXGRP) ? 'x' : '-',(mode & S_IROTH) ? 'r' : '-',(mode & S_IWOTH) ? 'w' : '-',(mode & S_IXOTH) ? 'x' : '-');
}int main(int argc, char *argv[]) {if (argc != 2) {fprintf(stderr, "用法: %s <文件名>\n", argv[0]);exit(EXIT_FAILURE);}struct stat sb;if (stat(argv[1], &sb) == -1) {fprintf(stderr, "stat() 失败: %s\n", strerror(errno));exit(EXIT_FAILURE);}printf("文件信息: %s\n", argv[1]);printf("========================\n");printf("文件类型: ");print_file_type(sb.st_mode);printf("\n");printf("权限: ");print_permissions(sb.st_mode);printf("\n");printf("硬链接数: %ld\n", (long) sb.st_nlink);printf("所有者UID: %d\n", sb.st_uid);printf("组GID: %d\n", sb.st_gid);printf("文件大小: %lld 字节\n", (long long) sb.st_size);printf("块大小: %ld 字节\n", (long) sb.st_blksize);printf("分配块数: %lld\n", (long long) sb.st_blocks);printf("最后访问: %s", ctime(&sb.st_atime));printf("最后修改: %s", ctime(&sb.st_mtime));printf("最后状态变更: %s", ctime(&sb.st_ctime));return 0;
}

7. 编译方式与注意事项

编译命令:

gcc -o stat_demo stat_demo.c

注意事项:

  1. 权限问题:需要对目标文件路径有执行权限才能成功调用 stat()
  2. 符号链接:使用 stat() 会跟随符号链接,如需获取链接本身信息,使用 lstat()
  3. 时间精度:不同系统可能支持不同精度的时间戳(秒、纳秒等)
  4. 可移植性struct stat 的具体字段可能因系统和架构而异
  5. 文件描述符:使用 fstat() 时,确保文件描述符有效且已打开
  6. 错误处理:始终检查返回值并处理可能的错误情况

8. 执行结果说明

假设有一个名为 test.txt 的文件,运行程序:

$ ./stat_demo test.txt

可能的输出:

文件信息: test.txt
========================
文件类型: 普通文件
权限: rw-r--r--
硬链接数: 1
所有者UID: 1000
组GID: 1000
文件大小: 1024 字节
块大小: 4096 字节
分配块数: 8
最后访问: Wed Jun 15 10:30:45 2023
最后修改: Wed Jun 14 16:20:30 2023
最后状态变更: Wed Jun 14 16:20:30 2023

结果解释:

  • 这是一个普通文件,权限为所有者可读写,组和其他用户只读
  • 文件大小为1024字节,但实际占用8个512字节的块(即4096字节,由于文件系统块大小)
  • 时间戳显示文件的最后访问、修改和状态变更时间

9. 图文总结

以下是 stat 系统调用的工作流程:

调用 statpath, &sb
系统处理请求
路径解析
是符号链接?
跟随链接
直接访问目标
读取文件元数据
填充struct stat
返回成功0
解析失败
读取失败
设置errno
返回-1

关键点总结:

  1. stat 提供了一种无需打开文件即可获取文件元数据的方法
  2. 三种变体 (stat, fstat, lstat) 适用于不同场景
  3. 返回的 struct stat 包含丰富的文件信息,如类型、权限、大小和时间戳
  4. 正确使用 stat 需要了解文件系统权限和路径解析规则
  5. 始终检查返回值并处理错误情况是良好编程实践

stat 系统调用是文件操作和系统编程的基础,深入理解其工作原理和用法对于开发可靠的系统软件至关重要。

http://www.dtcms.com/a/352372.html

相关文章:

  • 学习碎片02
  • Firefox Relay 体验
  • Redis支持事务吗?了解Redis的持久化机制吗?
  • 面试八股文之——Java集合
  • 115、【OS】【Nuttx】【周边】效果呈现方案解析:重定向命令
  • Python编程快速上手—让繁琐工作自动化
  • 论文阅读-CompletionFormer
  • (我与爬虫的较量)码上爬第5题
  • JDK 8 → JDK 17 升级说明书(面向 Spring Boot / Spring Cloud / Spring )
  • Filter过滤器入门
  • android 事件处理源码
  • 当 AI 走进日常:除了聊天机器人,这些 “隐形应用” 正在改变我们的生活
  • 报告:2025机器人技术产业化研究|附130+份报告PDF、数据仪表盘汇总下载
  • 直播到AI助教:在线教育系统源码如何重塑知识付费平台生态?
  • 算法练习——26.删除有序数组中的重复项(golang)
  • 电影感氛围人像风光摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!
  • 抖音多账号管理平台哪家比较好?
  • 力扣 30 天 JavaScript 挑战 第40天 (第十一题)对纯函数和记忆函数有了更深理解
  • ABC420A-E题解
  • Zynq开发实践(FPGA之verilog仿真)
  • leetcode算法刷题的第十八天
  • 【世纪龙科技】职业院校汽车专业职业体验中心建设方案
  • 面试题随笔
  • 微服务-25.网关登录校验-网关传递用户到微服务
  • 微服务的编程测评系统16-用户答题
  • 【typenum】30 类型级别的取负(Neg)
  • `mmap` 系统调用详解
  • 设备驱动程序 day62
  • 变压器副边电流计算
  • es-toolkit 是一个现代的 JavaScript 实用库