调用 stat() 或 lstat() 填充 struct stat 后,st_ino 成员即为 inode 号;需配合 st_dev 判定唯一性,跨文件系统或无 inode 文件系统(如 fat32)中不可靠。

怎么用 stat() 拿到文件的 inode 号
直接调用 stat() 函数,填好路径和 struct stat 缓冲区就行。关键不是“能不能”,而是“传什么路径、用哪个函数、结构体里哪成员是 inode”。Linux/macOS 下 st_ino 就是你要的 inode 号,但注意:它只在同一个文件系统内唯一;跨挂载点比较毫无意义。
常见错误是传了符号链接路径却没意识到默认会跟随——结果拿到的是目标文件的 inode,不是链接本身的。这时候得换 lstat()。
-
stat("path/to/file", &sb):跟随符号链接,取目标 inode -
lstat("path/to/link", &sb):不跟随,取链接文件自身的 inode - 路径必须是绝对路径或相对于当前工作目录的有效路径;相对路径出错时
errno通常是ENOENT或EFAULT
st_ino 在不同文件系统上的行为差异
inode 是文件系统内部概念,st_ino 的值完全由底层 fs 决定。ext4、XFS、Btrfs 都给,但 NTFS(通过 WSL 或 FUSE)可能返回 0 或伪造值;FAT32/ExFAT 根本没有 inode,glibc 会硬塞一个基于路径哈希的伪 inode,每次 mount 都可能变。
所以别拿 st_ino 做跨机器、跨重启的持久标识。真要唯一识别文件,得结合 st_dev(设备号)+ st_ino,而且仅限同一台机、同一挂载状态下有效。
- 检查是否支持真实 inode:
stat -c "%d %i" /some/file,如果%i总是 0 或重复,大概率是无 inode 文件系统 -
st_dev不等于磁盘设备号,而是内核分配的文件系统实例 ID,相同挂载点多次 mount 会不同 - 容器里跑程序时,
/proc和/sys下的文件常返回特殊 inode(如 1),不能当普通文件处理
为什么 fstat() 比 stat() 更安全
当你已经打开了文件(比如用 open() 得到 fd),优先用 fstat(int fd, struct stat *buf)。它不依赖路径字符串,绕过路径解析、权限检查、竞态窗口——哪怕文件被 rename 或 unlink,只要 fd 没关,fstat() 仍能读到原始 inode 信息。
典型误用是:先 stat() 判断文件存在,再 open(),中间被删掉就崩了。用 open(O_NOFOLLOW | O_CLOEXEC) + fstat() 一气呵成更稳。
- fd 必须是合法打开的,关闭后调
fstat()会返回EBADF -
fstat()不刷新文件内容状态(比如 mtime),它读的是内核中该 fd 对应的 inode 缓存快照 - 对管道、socket、终端等非普通文件,
st_ino可能为 0,此时看st_mode & S_IFMT类型位更可靠
struct stat 成员里哪些和 inode 强相关
st_ino 是核心,但单靠它不够。真正做文件身份判定时,至少要看三个字段:st_dev(所在文件系统)、st_ino(节点号)、st_mode(类型掩码)。漏掉 st_dev 就像只记身份证号不记省份,两台机器上完全可能撞号。
另外注意:某些旧代码把 st_ino 当 long 用,但在 x86_64 Linux 上它是 unsigned long,而 macOS 是 uint64_t;直接 printf("%ld", sb.st_ino) 在 macOS 上会截断。
- 打印 inode 安全写法:
printf("%ju", (uintmax_t)sb.st_ino) -
st_nlink表示硬链接数,可辅助判断是否被其他路径引用,但它不是 inode 的一部分,只是 inode 的一个属性 - 不要用
st_ctime推测 inode 创建时间——它记录的是元数据变更时间,且很多文件系统根本不存创建时间
inode 不是万能 ID,它脆弱、不可移植、受文件系统制约。真要稳定追踪文件,要么用文件内容 hash,要么走内核 inotify/fanotify + fd 绑定,别死磕 st_ino。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











