os.Stat与os.Lstat核心区别在于是否穿透软链接:Stat跟随软链接获取目标文件元数据,Lstat仅返回软链接自身元数据;硬链接因共享inode,两者结果相同。

Go 里 os.Stat 和 os.Lstat 到底差在哪
区别就一条:遇到软链接时,os.Stat 会顺着链接走到目标文件再读元数据;os.Lstat 则只读软链接自身的元数据(比如它自己的大小、创建时间、权限),不穿透。
硬链接没有这个穿透问题——因为硬链接和原文件共享同一个 inode,Stat 和 Lstat 返回结果完全一样。所以“区分软硬链接”本质上就是“要不要穿透软链接”。
- 想检查一个路径是不是软链接?必须用
os.Lstat,然后看fi.Mode()&os.ModeSymlink != 0 - 想获取软链接指向的目标路径?用
os.Readlink(path),不是从Stat结果里拿 - 想判断软链接是否有效(目标存在)?得先
Lstat确认是链接,再Stat目标路径,或直接os.Open尝试访问
什么时候该用 os.Lstat 而不是 os.Stat
典型场景是做文件系统遍历、权限审计、备份工具或符号链接管理器。比如你写个 ls -l 的简化版,要显示 lrwxr-xr-x 这种带 l 前缀的权限位,就必须用 Lstat ——否则软链接会被当成它指向的文件类型(比如普通文件),永远看不到那个 l。
- 检查路径是否存在且是软链接:
fi, err := os.Lstat(path); if err == nil && fi.Mode()&os.ModeSymlink != 0 - 避免意外跟随损坏链接导致 panic:
os.Stat在软链接指向不存在路径时会返回os.ErrNotExist,而Lstat只要链接文件本身存在就成功 - 硬链接无需特殊处理:无论用哪个函数,得到的
fi.Sys().(*syscall.Stat_t).Ino都一样
os.Lstat 返回的 os.FileInfo 里哪些字段不可信
软链接自身的 Size() 返回的是链接路径字符串的字节数(比如 ../bin/sh 是 10),不是目标文件大小;ModTime() 是软链接本身的修改时间(即最后一次调用 ln -sf 的时间),和目标无关;IsDir()/IsRegular() 也基于链接自身模式位,永远返回 false(除非是目录软链接,但仍是 ModeSymlink)。
立即学习“go语言免费学习笔记(深入)”;
- 别用
fi.Size()估算磁盘占用——它对软链接毫无意义 - 别依赖
fi.ModTime()判断目标文件是否更新 - 判断目标类型?得先
os.Readlink拿到路径,再os.Stat它
跨平台兼容性注意点:Windows 上的软链接行为
Windows 从 Vista 开始支持符号链接,但需要管理员权限创建,且 Go 的 os.Lstat 在 Windows 上仍能正确识别 ModeSymlink。不过要注意:os.Readlink 在 Windows 上可能返回空字符串或错误(尤其面对 junction 或快捷方式时),而 junction(目录重解析点)不会被标记为 ModeSymlink,它走的是另一套机制。
- 不要假设所有“类似链接”的东西都满足
ModeSymlink——Windows 的 junction、mklink /D、甚至某些第三方快捷方式都不算 - 在 CI 或容器环境测试时,Linux 默认允许普通用户建软链接,Windows Docker Desktop 默认禁用,容易漏掉路径失效问题
- 如果业务逻辑强依赖链接解析,建议封装一层
ResolveLink函数,内部先Lstat,再Readlink,最后Stat目标,并统一处理filepath.Join路径拼接(避免..解析出错)
Lstat 还是 Stat 来决定。没人替你做这个选择,也没法靠一次调用同时拿到两边信息。










