os.Open返回*os.PathError时需用errors.Is(err, os.ErrNotExist)判断文件不存在,或errors.Is(err, os.ErrPermission)判断权限问题;类型断言可获取pe.Err进一步判断syscall错误;defer前必须确保f非nil。
os.Open 返回 *os.PathError 时怎么判断具体错误类型
Go 的文件操作错误不是简单布尔值,os.Open 失败时返回的 *os.PathError 包含底层原因,直接用 err == nil 只能知道成败,无法区分是“文件不存在”还是“权限不足”。
正确做法是用 errors.Is 或类型断言:
-
errors.Is(err, os.ErrNotExist)判断是否因文件不存在失败(兼容 symlink、目录等场景) -
errors.Is(err, os.ErrPermission)检查权限问题 - 需要更细粒度控制时,做类型断言:
if pe, ok := err.(*os.PathError); ok && pe.Err == syscall.EACCES
注意:不要用 strings.Contains(err.Error(), "no such file") —— 错误文本不保证稳定,跨系统/语言可能变化。
defer f.Close() 前忘记检查 f 是否为 nil 会 panic
os.Open 失败时返回 nil, err,如果直接写 defer f.Close() 而没检查 f,后续调用 defer 时会 panic:panic: runtime error: invalid memory address or nil pointer dereference。
安全写法只有两种:
- 在
if err != nil分支里 return,确保f非 nil 后再 defer:f, err := os.Open("x.txt"); if err != nil { return err }; defer f.Close() - 或显式判空:
if f != nil { defer f.Close() }(仅适用于不能立即 return 的复杂逻辑)
别依赖 “反正 defer 不会立刻执行” 来绕过检查 —— 这是常见侥幸心理,实际极易漏掉。