Go 中 os.Stat 无法获取硬链接数,因 FileInfo 不暴露该字段;需用 syscall.Stat(Unix)或 syscall.GetFileInformationByHandle(Windows)访问底层 inode 属性,且跨平台需构建约束和降级处理。

Go 中用 os.Stat 获取硬链接数不准确?
直接调用 os.Stat 返回的 os.FileInfo 不暴露硬链接数量,它只提供基础元信息(如大小、修改时间),Links() 方法根本不存在。这是初学者常踩的坑——误以为 FileInfo 包含所有 inode 信息。
硬链接数属于底层 inode 属性,必须通过系统调用访问。Go 的标准库不跨平台暴露该字段,但提供了 syscall.Stat_t(Unix)和 syscall.Win32FileAttributeData(Windows)等底层结构体。
- Linux/macOS:用
syscall.Stat获取syscall.Stat_t.Nlink - Windows:NTFS 不支持传统硬链接计数语义,
GetFileInformationByHandle返回的nNumberOfLinks仅对硬链接文件有效,且需管理员权限创建;普通文件该值恒为 1 - 跨平台代码必须做构建约束(
//go:build unix)并 fallback 处理
syscall.Stat 在 Linux/macOS 上怎么取 Nlink
需要绕过 os.Stat,直接调用 syscall 接口。注意:syscall.Stat 参数是路径字符串,不是 *os.File,且返回的是 C 风格 struct,字段名大小写敏感(Nlink 是大写 N)。
package main
import (
"fmt"
"syscall"
"unsafe"
)
func getHardLinkCount(path string) (uint64, error) {
var stat syscall.Stat_t
if err := syscall.Stat(path, &stat); err != nil {
return 0, err
}
return uint64(stat.Nlink), nil
}
func main() {
n, _ := getHardLinkCount("/etc/passwd")
fmt.Println("hard link count:", n) // 输出通常是 1 或更大(取决于是否被硬链接)
}
-
stat.Nlink类型是uint64(Linux)或uint16(macOS),统一转uint64更安全 - 路径必须存在且可访问,否则
syscall.Stat返回ENOENT或EACCES - 不能对符号链接本身调用——
syscall.Stat跟随 symlink;要用syscall.Lstat获取 symlink 自身的 inode 信息(此时Nlink恒为 1)
为什么 os.Lstat + syscall.Stat_t 组合更可靠
os.Lstat 返回 os.FileInfo,但它内部其实也调用了 syscall.Lstat。问题在于:标准库未导出底层 syscall.Stat_t 实例。所以正确姿势是——先用 os.Lstat 确保路径合法性并获取 os.FileMode,再用 syscall.Lstat 取 Nlink。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
立即学习“go语言免费学习笔记(深入)”;
- 避免重复 open:先
os.Lstat检查是否存在、是否为目录、是否有权限,再决定是否调用 syscall - 符号链接场景必须用
syscall.Lstat,否则syscall.Stat会解析目标,得到的是目标文件的链接数,不是 symlink 自身的 - macOS 上
syscall.Stat_t字段名是Nlink,但某些旧内核可能用Nlink32,建议始终用go version >= 1.18并依赖golang.org/x/sys/unix替代原生syscall
实际项目中容易忽略的边界点
硬链接数不是“当前路径有多少个硬链接”,而是“该 inode 被多少个目录项引用”。这意味着:
- 同一文件系统内多个路径指向同一 inode 才算硬链接;跨文件系统(如 /home 和 /tmp 分属不同 mount)不可能有硬链接
- 容器或 overlayfs 场景下,
Nlink可能被虚拟化层篡改,返回值不可信 - 某些 NFS 服务器不维护或不透传
nlink,返回值恒为 1 - Go 1.22+ 推荐用
golang.org/x/sys/unix替代syscall,后者已标记 deprecated,且unix.Stat返回的unix.Stat_t字段更稳定
真正要判断“这个文件是否被硬链接过”,不能只看 Nlink > 1,还得确认它是否在支持硬链接的文件系统上——比如 ext4、XFS 可以,btrfs 默认关闭,ZFS 需显式启用。

















