当前位置: 首页 > 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.xdnf.cn/news/1370503.html

相关文章:

  • AI应用--接口测试篇
  • 实训日志day28
  • Elasticsearch中的设置refresh_interval
  • 文献阅读笔记【雷达辐射源识别】:Recognition of Unknown Radar Emitters with Machine Learning
  • 浅谈ArrayList的扩容机制
  • Nginx配置学习及多应用场景配置示例
  • 验证码请求与缓存问题解决方案
  • Leetcode—1163. 按字典序排在最后的子串【困难】
  • 智慧园区:从技术赋能到价值重构,解锁园区运营新范式
  • 产品经理成长手册(2)——产品文档能力
  • 二、JVM 入门——(三)栈
  • 两数之和,leetCode热题100,C++实现
  • 链改2.0六方会谈协同创新—可信资产IPO与数链金融RWA双轮驱动
  • 第17章|PowerShell 安全警报——高分学习笔记(运维实战向)
  • 使用Kiro智能开发PYTHON应用程序
  • onnx入门教程(五)——实现 PyTorch-ONNX 精度对齐工具
  • Ubuntu操作系统下MySQL、MongoDB、Redis
  • 基于 LQG 控制的轨迹跟踪 —— 从原理到实践
  • 优雅草黑曼巴知识付费项目交付顺带:深入剖析 WebApp 的封装原理与实践-卓伊凡
  • MD5校验算法
  • FreeRTOS 同步互斥与任务协作 学习笔记
  • vscode或者cursor配置使用Prettier - Code formatter来格式化微信小程序wxss/wxs/wxml文件
  • CentOS 7 升级 OpenSSL 3.5.1 的详细教程
  • HarmonyOS image组件深度解析:多场景应用与性能优化指南(2.4详细解析,完整见uniapp官网)
  • Android 属性 property 系统
  • 微服务的编程测评系统16-用户答题
  • 什么是索引下推?
  • ADB 安装教程:如何在 Windows、 Linux 上安装 Android Debug Bridge
  • 基于CSO与BP神经网络分类模型的特征选择方法研究(Python实现)
  • 2025第五届人工智能、自动化与高性能计算国际会议 (AIAHPC 2025)