os.Open后必须检查err,否则file可能为nil,后续Read或Close将panic;需用os.IsNotExist等函数判断错误类型,Close和Write错误也不可忽略。

os.Open 之后必须检查 err,否则可能 panic
Go 的 os.Open 不会自动 panic,但返回的 file 在 err != nil 时大概率是 nil。如果忽略错误直接调用 file.Read() 或 file.Close(),会触发 nil pointer dereference panic。
- 错误写法:
file := os.Open("config.txt")—— 没接收err,后续调用必崩 - 正确写法:
f, err := os.Open("config.txt"),紧接着if err != nil判断 - 即使
err != nil,f也可能非nil(极少数系统调用部分成功),但 Go 标准库约定:此时应忽略f,不调用任何方法
区分 os.IsNotExist 和 os.IsPermission 等具体错误类型
不能只靠 err.Error() 字符串匹配(比如 strings.Contains(err.Error(), "no such file")),跨平台行为不一致,且易被底层 syscall 错误消息格式变更破坏。
- 用
os.IsNotExist(err)安全判断“文件不存在”,它内部做了类型断言和 syscall 错误码比对 - 同理,
os.IsPermission(err)判断权限不足,os.IsTimeout(err)判断超时(如网络挂载文件系统) - 若需更细粒度控制(例如区分
syscall.ENOSPC磁盘满),可做*os.PathError类型断言,再检查pathErr.Err
os.ReadFile 更简洁,但要注意内存与错误包装
os.ReadFile(Go 1.16+)内部封装了打开、读取、关闭全过程,适合小文件(MB 级以内)。但它仍返回原始错误,不自动添加上下文。
- 直接使用:
data, err := os.ReadFile("config.json"),仍需if err != nil - 推荐包装错误:
return nil, fmt.Errorf("加载配置文件 %q 失败: %w", path, err),保留原始错误链 - 大文件慎用:一次性加载可能 OOM;GB 级文件必须用
os.Open+ 流式读取(如bufio.Scanner或分块io.ReadFull)
Close() 的错误不能忽略,尤其写入场景
defer f.Close() 很方便,但 Close() 本身可能失败(如写入缓冲未刷盘、磁盘满、NFS 断连)。对读操作影响小,但写操作中忽略 Close() 错误可能导致数据丢失而不自知。
立即学习“go语言免费学习笔记(深入)”;
- 安全写法:
if err := f.Close(); err != nil { log.Printf("关闭文件 %q 失败: %v", path, err) } - 写入后必须检查:
_, err := f.Write(data)之后,err可能为nil,但Close()才真正落盘,它失败才是最终写入失败 - 若需强一致性,建议用
file.Sync()显式刷盘,再Close(),并检查两者错误
Close() 错误检查和错误包装的上下文缺失。前者让写入失败静默,后者让日志里只看到 read: no such file,却不知道这个读发生在哪个模块、哪次请求、用了什么路径——排查时只能靠猜。


















