Go中处理文件写入错误需同时检查Write返回的n和err,因err==nil时n可能小于预期;推荐用io.WriteFull确保全量写入,或结合Sync/Flush保证落盘。
在 Go 中处理文件写入错误,核心是检查 Write 方法的返回值(n int 和 err error),而不是只关注 err 是否为 nil。因为即使 err == nil,n 也可能小于预期字节数,说明写入不完整——这在某些场景(如网络文件系统、磁盘满、信号中断)下真实存在。
Write(p []byte) (n int, err error) 的语义是:最多写入 len(p) 字节,实际写入 n 字节,若发生错误则返回非 nil err。注意:
os.File.Write 在多数情况下会尝试写完全部,但不保证——尤其在非 POSIX 环境或封装的 Writer 上io.WriteString、fmt.Fprint* 等也最终调用 Write,同样需检查其返回的 error若业务要求「要么全写入,要么失败」,不要手动拼接 Write 循环,而应使用标准库提供的健壮工具:
io.WriteFull(w io.Writer, b []byte):确保写入全部 b,返回 n == len(b) 或第一个遇到的 error;适合小到中等数据io.Copy 或 w.Write(p) + 显式校验:例如写入后调用 file.Sync() 保证落盘,并检查 Sync() 的 error很多问题不是出在 Write,而是前置或后续步骤:
f, err := os.OpenFile(...) 后直接用 f.Write,但 err != nil 会导致 panic 或静默失败defer f.Close(),否则可能因 fd 耗尽导致后续 Write 失败(报 too many open files)bufio.Writer)需显式 Flush();关键数据建议 file.Sync() 确保写入磁盘syscall.EAGAIN 或 syscall.EINTR 在某些 Writer 上可重试,但标准 os.File.
Write 已内部处理,一般无需手动重试兼顾可读性与健壮性:
func writeFileAtomic(path string, data []byte) error {
f, err := os.Create(path + ".tmp")
if err != nil { return err }
defer f.Close()
if _, err = io.WriteFull(f, data); err != nil {
return err
}
if err = f.Sync(); err != nil {
return err
}
return os.Rename(path+".tmp", path)
}