直接调用stat()函数并传入有效路径,检查返回值为0后读取sb.st_ino即可获取inode号;需注意路径有效性、权限及符号链接处理,推荐配合st_dev使用以确保唯一性。

怎么用 stat() 拿到真正的 inode 号
直接调用 stat() 是最常用也最稳妥的方式,但前提是路径有效、权限足够,且你检查了返回值。不检查返回值就直接读 sb.st_ino,大概率拿到的是未初始化的垃圾值——尤其当路径不存在或权限被拒时,stat() 返回 -1,errno 会是 ENOENT 或 EACCES。
必须做这三件事:
- 传入绝对路径,或确保当前工作目录稳定(比如用
getcwd()拼接相对路径) - 检查
stat()返回值是否为 0;非 0 时sb.st_ino和sb.st_dev未定义 - 若要区分符号链接本身和它指向的目标,用
lstat()而不是stat()—— 后者默认跟随链接
示例片段:
#include <sys/stat.h>
struct stat sb;
if (stat("/tmp/data.txt", &sb) == 0) {
printf("inode: %lu, device: %lu\n", (unsigned long)sb.st_ino, (unsigned long)sb.st_dev);
} else {
perror("stat failed");
}
为什么 fstat() 比 stat() 更可靠
当你已经通过 open() 拿到了文件描述符(fd),就该无条件优先用 fstat()。它不依赖路径字符串,绕过整个 VFS 路径查找流程,自然也就避开了 symlink 解析、挂载点切换、竞态删除等一堆麻烦事。
立即学习“C++免费学习笔记(深入)”;
典型翻车场景:
- 先
stat()判断文件存在,再open()—— 中间文件被unlink(),第二步就失败 - 从
/proc/self/fd/读出路径再stat(),结果路径带(deleted)后缀,stat()必然报ENOENT
而只要 fd 还合法(没 close),fstat(fd, &sb) 就能稳稳读出原始 inode 信息,哪怕文件早已被删、重命名或移动。
根据 package.json 中的 engines 字段自动检测 Node.js 版本需求,未安装 nvm 时自动安装并切换至对应版本。支持 Windows、macOS、Linux。适用于 Node.js 项目开发、版本切换和环境配置。
注意:fd 必须是打开成功的,关闭后调用 fstat() 会返回 EBADF;对 pipe/socket 等特殊 fd,st_ino 可能为 0,此时应结合 st_mode & S_IFMT 判断类型。
st_ino 和 st_dev 怎么组合才真正唯一
单看 st_ino 没有意义:它只在同一个文件系统内唯一。跨挂载点、跨设备、跨重启,甚至跨 mount 实例(如 bind mount),st_ino 都可能重复或失效。
真正能标识一个“物理文件”的最小组合是 st_dev + st_ino,但仍有边界条件:
-
st_dev是内核分配的文件系统实例 ID,不是磁盘设备号;相同分区多次 mount,st_dev可能不同 - FAT32/ExFAT 等无 inode 文件系统,glibc 会伪造
st_ino(基于路径哈希),每次 mount 都可能变 - 容器中
st_dev可能被 namespace 隔离,宿主机与容器内值不一致 -
/proc、/sys下的文件常返回固定st_ino(如 1),不能当真实 inode 用
所以别拿 st_ino 做持久化 ID 或跨机器比对。真要唯一识别,得加一层业务逻辑:比如限制在同一台机器、同一挂载生命周期内,且明确排除伪文件系统。
常见误读:别把 st_rdev 当 st_dev
st_dev 是文件所在存储设备的 ID,所有普通文件、目录都靠它定位物理/虚拟设备;st_rdev 只对字符/块设备文件(如 /dev/sda)有意义,表示它“代表”的底层硬件设备号。
错误做法:
- 对普通文件读
st_rdev,值无意义,可能是 0 或随机数 - 用
mknod创建的设备文件,st_dev是它自己存放在哪个分区,st_rdev才是它模拟的设备号(比如主次号 8:0) - 混淆
stat -c "%d %i" /path输出中的%d(即st_dev)和%i(即st_ino)
一句话:查普通文件元数据,只碰 st_dev 和 st_ino;只有处理 /dev/xxx 类型时,才需要关心 st_rdev。


















