不可靠。os.Stat 不能直接用 err != nil 判断文件不存在,必须用 os.IsNotExist(err) 区分“不存在”与其他错误;更推荐直接读取并处理 os.IsNotExist,避免竞态和多余系统调用。

用 os.Stat 判断文件是否存在是否可靠?
不可靠。直接调用 os.Stat 并检查错误类型来判断“不存在”,容易误判其他错误(如权限不足、路径过长、设备忙等),导致逻辑错误。
os.Stat 返回的错误必须用 os.IsNotExist 检查
Go 的 os.Stat 在文件不存在时返回的是一个包装过的错误,不能用字符串匹配或 == nil 简单判断。必须用标准库提供的判定函数:
-
os.IsNotExist(err):仅在文件或目录**确实不存在**时返回true -
os.IsPermission(err):权限不足(比如对父目录无读/执行权) -
os.IsExist(err):用于Create等场景,和Stat关系不大
fi, err := os.Stat("config.json")
if err != nil {
if os.IsNotExist(err) {
// 文件真的不存在
log.Println("config.json not found")
} else {
// 其他错误:可能是 permission denied / too many symlinks / I/O error...
log.Printf("stat failed: %v", err)
}
return
}
// 此时 fi 是有效的 *os.FileInfo
更简洁安全的做法:用 os.ReadFile 或 os.Open 直接尝试读取
如果最终目标是读文件内容,没必要先 Stat 再读——两次系统调用,且仍需处理中间错误。直接读并用 os.IsNotExist 分支处理即可:
- 避免竞态:
Stat后文件被删除,再Open仍会失败 - 减少 syscall 开销:一次系统调用比两次快
- 代码更直白:意图就是“读这个文件”,不是“查它存不存在”
data, err := os.ReadFile("settings.yaml")
if err != nil {
if os.IsNotExist(err) {
// 使用默认配置
data = []byte("timeout: 30\n")
} else {
return fmt.Errorf("read settings: %w", err)
}
}
cfg := parseYAML(data)
注意:os.Stat 对符号链接的处理会影响判断结果
os.Stat 默认解析符号链接(即返回目标文件的信息),如果目标不存在,会报 os.IsNotExist;但如果你需要判断“链接文件本身是否存在”,得用 os.Lstat:
立即学习“go语言免费学习笔记(深入)”;
-
os.Stat("link")→ 检查链接指向的目标是否存在 -
os.Lstat("link")→ 检查link这个路径上的符号链接文件是否存在(即使它指向一个坏目标)
多数场景用 Stat 就够了,但做文件系统工具类逻辑时,这点容易被忽略。










