需调用 stat() 填充 struct stat 并检查返回值,st_ino 与 st_dev 组合唯一标识文件;用 lstat() 获取软链接自身 inode;包含 和 。

直接用 stat() 系统调用获取 st_ino,但仅靠它无法安全去重——必须搭配 st_dev 才构成跨文件系统唯一的标识对。
怎么用 C++ 调用 stat() 正确读取 inode 号
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 <sys></sys>和#include <unistd.h></unistd.h>,否则编译不过
示例片段:
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?必须组合 st_dev 才能去重
st_ino 在单个挂载点内唯一,但不同设备(比如 / 和 /home 可能是不同磁盘或 LVM 逻辑卷)上完全可能重复。拿两个 st_ino == 12345 的文件,一个在 SSD 上、一个在 NFS 挂载点上,它们毫无关系。
立即学习“C++免费学习笔记(深入)”;
- 真正唯一标识一个文件的是二元组
(st_dev, st_ino) -
st_dev是设备号(主+次号打包),可用major(sb.st_dev)/minor(sb.st_dev)拆解,但通常直接比较原始值更稳妥 - NFS 场景下
st_dev可能被服务端统一映射成伪设备号,此时(st_dev, st_ino)仍不跨客户端唯一——如果你在集群中做全局去重,得额外加主机标识 - ext4/xfs 等本地文件系统中,
st_ino就是磁盘 inode 表的真实槽位索引,重启不变,但依然不能脱离st_dev单独使用
硬链接去重 vs 内容去重:两种场景对应不同逻辑
用 (st_dev, st_ino) 只能识别硬链接(同一份数据的多个入口)。如果文件名不同、路径不同、但内容一样(非硬链接),这个组合完全无效——它们的 st_ino 必然不同。
- 硬链接去重:遍历目录,对每个文件调用
stat(),用std::map<:pair ino_t>, std::vector<:string>></:string></:pair>分组,同 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 都可能失真,硬编码去重逻辑大概率失效。



















