发布于2026-07-17 阅读(0)
扫一扫,手机访问
说到 Linux 下用 C++ 获取文件 inode,很多人第一反应就是 stat() 系统调用。但这里有个关键点:st_ino 本身并不可靠,必须和 st_dev 组合起来,才能形成一个跨文件系统的唯一标识对。否则,去重逻辑很容易翻车。
Linux 没有所谓的“C++ 原生 inode API”,一切还得靠 POSIX 系统调用。核心就是把 struct stat 填满,其中 st_ino 就是你要的值——但前提是调用成功,路径有效。
stat() 默认不跟随符号链接,如果你想获取软链接自身(而不是它指向的目标)的 inode,那就得用 lstat()。if (stat(path.c_str(), &sb) != 0),否则 sb.st_ino 里全是随机垃圾,用了就出大事。errno 会变成 ENOENT 或 ELOOP)。#include 和 #include ,少了这两个头文件,编译直接报错。举个最简单的例子:
struct stat sb;
std::string path = "/tmp/test.txt";
if (stat(path.c_str(), &sb) == 0) {
std::cout << "inode: " << sb.st_ino << ", dev: " << sb.st_dev << "\n";
} else {
perror(("stat " + path).c_str()); // 自动打印 errno 对应的错误信息
}
st_ino 在单个挂载点内是唯一的,但不同设备(比如根目录 / 和 /home 可能是不同磁盘或 LVM 逻辑卷)上完全可能重复。举个例子:两个文件 st_ino == 12345,一个在 SSD 上,一个在 NFS 挂载点上,它们之间没有任何关系。
(st_dev, st_ino)。st_dev 是设备号(主设备号+次设备号打包在一起),可以用 major(sb.st_dev) / minor(sb.st_dev) 拆解,但通常直接比较原始值更稳妥。st_dev 可能被服务端统一映射成伪设备号,此时 (st_dev, st_ino) 在客户端之间仍然不唯一——如果你在集群中做全局去重,还得额外加上主机标识。st_ino 就是磁盘 inode 表的真实槽位索引,重启不变,但依然不能脱离 st_dev 单独使用。用 (st_dev, st_ino) 只能识别硬链接(同一份数据的多个入口)。如果文件名不同、路径不同,但内容一样(非硬链接),这个组合完全无效——它们的 st_ino 必然不同。
stat(),用 std::map, std::vector> 分组,同一个 key 的路径就是一组硬链接。SHA256),以哈希值作为 key。大文件要流式读取,避免内存爆掉;小文件可以直接 read() 全量。find . -samefile target 底层就是靠 stat() + (st_dev, st_ino) 实现的,但它只查硬链接,别误以为它能找内容重复文件。stat() 比哈希快得多,但只能解决一类问题。混用时建议先做硬链接聚类(零成本),再对每组代表文件做哈希校验(减少哈希次数)。相对路径、符号链接、当前工作目录(cwd)三者一搅和,stat() 的结果就可能出乎意料。
stat(),实际解析依赖调用时的 cwd——多线程或 chdir 后极易错乱。强烈建议先转成绝对路径(realpath())再调用。stat();想判断是否是同一个链接文件自身(比如监控谁改了这个链接),用 lstat()。stat() 遇到深层嵌套的符号链接(如 a→b→c→d)会递归解析,可能触发多次 I/O,甚至卡住(某些 overlayfs 或旧内核下)。lstat() 则立刻返回,适合快速扫描。/proc/mounts 显示的挂载点可能和宿主机不一致,st_dev 值不可跨容器直接比较。最麻烦的其实是 NFS + 符号链接 + 相对路径组合——这时候 st_ino 和 st_dev 都可能失真,硬编码去重逻辑大概率失效。

售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8