在Linux文件系统中,每个文件或目录都对应一个唯一的Inode节点,该节点存储了文件的所有底层元数据,包括文件类型、权限、所有者、大小、创建时间、修改时间、访问时间以及对应的Inode编号等信息。C++在Linux环境下可以通过stat系统调用来获取这些Inode元数据,这是操作系统提供的标准文件属性查询接口。

stat系统调用基本说明
stat是Linux系统提供的用于获取文件属性的系统调用,对应的C标准库函数声明在<sys/stat.h>头文件中,函数原型如下:
#include <sys/stat.h> #include <unistd.h> int stat(const char *pathname, struct stat *statbuf);
函数接收两个参数,第一个是目标文件的路径字符串,第二个是指向<code>struct stat</code>结构体的指针,函数执行成功会返回0,失败返回-1并设置errno。除了stat之外,还有lstat和fstat两个相关函数:lstat不会跟随符号链接,会直接返回符号链接本身的属性;fstat通过已打开的文件描述符来获取文件属性。
struct stat结构体字段解析
stat系统调用获取到的所有Inode元数据都存储在<code>struct stat</code>结构体中,该结构体的完整定义如下:
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; /* 分配给文件的块数量 */
struct timespec st_atim; /* 最后访问时间 */
struct timespec st_mtim; /* 最后修改时间 */
struct timespec st_ctim; /* 最后状态变更时间 */
};
其中<code>st_mode</code>字段需要配合宏定义来判断文件类型,常用的判断宏包括:
- <code>S_ISREG(st_mode)</code>:判断是否为普通文件
- <code>S_ISDIR(st_mode)</code>:判断是否为目录
- <code>S_ISLNK(st_mode)</code>:判断是否为符号链接
- <code>S_ISCHR(st_mode)</code>:判断是否为字符设备文件
- <code>S_ISBLK(st_mode)</code>:判断是否为块设备文件
- <code>S_ISFIFO(st_mode)</code>:判断是否为管道文件
- <code>S_ISSOCK(st_mode)</code>:判断是否为套接字文件
C++获取Inode元数据完整示例
下面是一个完整的C++示例,演示如何通过stat系统调用获取指定文件的Inode元数据并打印所有关键信息:
#include <iostream>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
// 将时间戳转换为可读的字符串格式
const char* format_time(const struct timespec* ts) {
static char time_str[64];
struct tm tm_time;
localtime_r(&ts->tv_sec, &tm_time);
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &tm_time);
return time_str;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
std::cerr << "使用方法: " << argv[0] << " 文件路径" << std::endl;
return 1;
}
const char* file_path = argv[1];
struct stat file_stat;
// 调用stat获取文件属性
if (stat(file_path, &file_stat) == -1) {
perror("stat调用失败");
return 1;
}
// 打印Inode编号
std::cout << "Inode编号: " << file_stat.st_ino << std::endl;
// 判断文件类型
std::cout << "文件类型: ";
if (S_ISREG(file_stat.st_mode)) {
std::cout << "普通文件";
} else if (S_ISDIR(file_stat.st_mode)) {
std::cout << "目录";
} else if (S_ISLNK(file_stat.st_mode)) {
std::cout << "符号链接";
} else if (S_ISCHR(file_stat.st_mode)) {
std::cout << "字符设备文件";
} else if (S_ISBLK(file_stat.st_mode)) {
std::cout << "块设备文件";
} else if (S_ISFIFO(file_stat.st_mode)) {
std::cout << "管道文件";
} else if (S_ISSOCK(file_stat.st_mode)) {
std::cout << "套接字文件";
} else {
std::cout << "未知类型";
}
std::cout << std::endl;
// 打印文件权限,转换为八进制显示
std::cout << "文件权限: " << std::oct << (file_stat.st_mode & 0777) << std::dec << std::endl;
// 打印文件大小
std::cout << "文件大小: " << file_stat.st_size << " 字节" << std::endl;
// 打印硬链接数量
std::cout << "硬链接数量: " << file_stat.st_nlink << std::endl;
// 打印所有者ID
std::cout << "所有者用户ID: " << file_stat.st_uid << std::endl;
std::cout << "所有者组ID: " << file_stat.st_gid << std::endl;
// 打印时间信息
std::cout << "最后访问时间: " << format_time(&file_stat.st_atim) << std::endl;
std::cout << "最后修改时间: " << format_time(&file_stat.st_mtim) << std::endl;
std::cout << "最后状态变更时间: " << format_time(&file_stat.st_ctim) << std::endl;
return 0;
}
编译运行该程序的命令如下:
g++ -o get_inode_info get_inode_info.cpp ./get_inode_info test.txt
常见问题说明
stat和lstat的区别
如果目标文件是符号链接,stat会跟随符号链接指向的实际文件获取属性,而lstat会直接返回符号链接本身的属性。如果需要判断符号链接本身的属性,应该使用lstat而不是stat。
权限不足的问题
如果当前进程没有访问目标文件的权限,stat调用会返回失败并设置errno为EACCES,此时需要检查进程的权限或者目标文件的权限设置。
跨文件系统的Inode唯一性
Inode编号只在同一个文件系统内是唯一的,不同文件系统上的文件可能有相同的Inode编号,因此不能仅通过Inode编号判断两个文件是否是同一个文件,需要结合<code>st_dev</code>字段(设备ID)一起判断。
C++stat系统调用Inode元数据文件系统struct_stat修改时间:2026-07-07 19:54:36