c++oding="utf-8" ?>
必须用 stat() 或其变体(如 lstat())读取 st_nlink 才可靠,因它是唯一可移植获取 inode 硬链接数的方式;readdir() 计数或解析 ls -l 均不可靠。

用 stat() 读取 st_nlink 是唯一可靠方式
Linux 下获取文件硬链接数,必须通过系统调用读取 inode 元数据,stat() 是标准且唯一可移植的途径。lstat() 和 fstat() 也能用,但语义不同:前者不跟随符号链接(推荐用于路径查询),后者需已有文件描述符。直接读取目录项或解析 ls -l 输出不可靠——那只是格式化后的快照,不是真实 inode 状态。
常见错误是误用 readdir() 遍历目录并计数文件名:这算的是目录项数量,不是该 inode 的硬链接数;一个文件可能在多个目录里有硬链接,也可能在同一个目录里有多个同 inode 的硬链接(虽然少见),单纯数名字完全失真。
-
stat("path/to/file", &sb)成功后,sb.st_nlink就是当前 inode 的硬链接数 - 若路径是符号链接,
stat()返回的是它指向的目标的st_nlink;要查符号链接自身(即 link 文件的 inode 链接数),得用lstat() -
st_nlink类型是nlink_t,通常是unsigned long,打印时用%lu,别用%d
st_nlink 的值为什么有时和 ls -l 显示不一致
不是 bug,是观察视角不同。比如执行 ls -l /proc/self/fd/ 会看到很多文件显示 st_nlink 为 0 —— 这是内核故意设的,因为 /proc 下的伪文件没有传统 inode 语义,st_nlink 无意义,内核填 0 表示“不适用”。普通磁盘文件不会这样。
另一个典型场景:NFS 或某些 FUSE 文件系统可能不准确报告 st_nlink,尤其在跨服务器硬链接支持不完整时。本地 ext4/xfs 没问题,但一上网络文件系统就得留个心眼。
- 目录的
st_nlink至少为 2:自身目录项 + 各子目录里的".."引用;每加一个子目录,st_nlink+1 - 删除文件时,只有当
st_nlink降为 0 且无进程打开它,磁盘空间才真正释放 - 硬链接只能对文件,不能对目录(root 除外),所以目录的
st_nlink永远不表示“有多少硬链接”,而是“有多少目录项引用这个 inode”
最小可运行示例:检查路径是否被多处硬链接
下面这段代码只做一件事:调用 lstat(),输出 st_nlink,并判断是否大于 1。它避开所有异常处理包装,直击核心逻辑。
#include <sys>
#include <stdio.h>
int main(int argc, char *argv[]) {
if (argc != 2) return 1;
struct stat sb;
if (lstat(argv[1], &sb) == 0) {
printf("st_nlink = %lu\n", (unsigned long)sb.st_nlink);
if (sb.st_nlink > 1) {
printf("→ 该路径对应 inode 至少被硬链接了 %lu 次\n", (unsigned long)sb.st_nlink);
}
} else {
perror("lstat");
}
return 0;
}
</stdio.h></sys>
编译:g++ -o linkcnt linkcnt.cpp(C++ 项目里混用 C 头没问题);运行:./linkcnt somefile。注意:必须用 lstat,否则符号链接会被穿透,拿到的是目标文件的链接数,不是你输入的那个路径本身的 inode 链接数。
硬链接数在 C++ 中没法绕过 C API 直接拿
标准 C++20 提供了 std::filesystem::status() 和 symlink_status(),但它们不暴露 st_nlink。GCC libstdc++ 和 Clang libc++ 都没把 nlink 塞进 file_status 或扩展属性里。想在 C++ 里拿到它,终究得调 stat() 或 lstat(),封装成 inline 函数即可,没必要强求“纯 C++”。
容易踩的坑是试图用 std::filesystem::is_regular_file() 一类函数替代元数据读取——它们内部也调 stat,但只提取布尔结果,把 st_nlink 扔掉了。性能上没差别,但信息丢了。
- 不要为了“用 C++ 标准库”而放弃
lstat();它稳定、精确、零额外开销 - 如果项目已用
std::filesystem::path,可以lstat(p.c_str(), &sb),安全又自然 -
st_nlink是瞬时值:两次调用stat()之间,其他进程可能增删硬链接,别缓存它做长期判断
硬链接数本身不难读,难的是理解它到底代表什么——它不是“文件被引用了多少次”的用户级概念,而是内核 inode 结构体里那个整数字段,含义严格绑定于文件系统实现和当前时刻。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











