用 os.stat 一次性检查存在性和获取大小最简洁可靠,应始终用 os.isnotexist(err) 判断不存在,避免误用 os.isexist 或仅凭 err != nil 推断;推荐封装为返回 (size, exists, err) 的函数,禁用 os.open+stat 组合以防资源泄漏。

用 os.Stat 一次性完成存在性检查和大小获取
直接调用 os.Stat 是最简洁可靠的方式,它不区分“文件不存在”和“权限不足”等错误,但能同时拿到 os.FileInfo,其中就包含大小(Size())。别先用 os.IsNotExist 判断再 Stat —— 多一次系统调用,还可能因竞态条件出错(比如判断存在后文件被删)。
常见错误是只检查 err == nil 就认为文件存在,却忽略 os.IsNotExist(err) 才是判断“不存在”的正确方式。
- 始终用
os.IsNotExist(err)判断文件是否真的不存在,而不是err != nil - 如果
err非空且不是os.IsNotExist,说明有其他问题(如权限拒绝、路径是目录但期望是文件),需按需处理 -
fi.Size()返回的是字节数,类型为int64,注意不要直接赋给int变量导致溢出
避免 os.IsExist 和 os.IsNotExist 的误用
os.IsExist 并不是“文件存在”的反义判断,它在 Go 1.13+ 中已明确标注为“不推荐用于检查文件是否存在”,它的语义其实是“操作失败是因为目标已存在”(例如 os.Mkdir 时路径已存在)。误用它来判断文件是否存在,会在 Windows 上返回意外的 true(比如对一个无读权限的路径),造成逻辑混乱。
真正该用的只有 os.IsNotExist —— 它专为“文件/目录不存在”这一错误设计,跨平台行为稳定。
- ✅ 正确:
if os.IsNotExist(err) { /* 文件不存在 */ } - ❌ 错误:
if os.IsExist(err) { /* 以为是存在 */ }(语义错、平台表现不一致) - ❌ 危险:
if err == nil { /* 存在 */ } else { /* 不存在 */ }(把 permission denied 当成不存在)
封装成可复用的函数:返回 (size int64, exists bool, err error)
把逻辑收拢成一个函数,签名清晰表达意图,调用方无需重复写错误分支。返回 exists bool 而不是 error,让业务代码更直白 —— 比如日志里直接写 if !exists { log.Printf("config.json not found") }。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
func FileSize(path string) (int64, bool, error) {
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return 0, false, nil
}
return 0, false, err
}
return fi.Size(), true, nil
}
注意这个函数不假设路径必须是普通文件;如果传入目录,fi.Size() 返回的是目录元数据占用(通常很小,非内容大小),这点需结合使用场景确认是否符合预期。
性能与兼容性提醒:别用 os.Open + Stat() 组合
有人会先 os.Open 再对 *os.File 调用 Stat(),这不仅多开一个 fd,还容易忘记 Close() 导致资源泄漏。而 os.Stat 是纯元数据查询,无打开动作,开销更低,也无须管理生命周期。
在容器或嵌入式环境里,fd 数量受限,这种冗余打开尤其危险。另外 os.Stat 在所有主流 OS(Linux/macOS/Windows)上行为一致,无需额外适配。
- ✅ 推荐:
os.Stat(path)—— 简洁、安全、高效 - ❌ 不推荐:
f, _ := os.Open(path); defer f.Close(); f.Stat() - ⚠️ 注意:
os.Stat对符号链接默认解析目标,如需获取链接本身信息,用os.Lstat
真正要小心的是把“不存在”和“不可读”混为一谈——前者是预期外缺失,后者可能是部署权限配置问题,两者在日志和告警策略里应区别对待。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










