用os.OpenFile配合os.O_APPEND|os.O_WRONLY|os.O_CREATE可安全追加写入;os.Create会清空文件,os.Open默认只读,均不满足末尾添加需求。

Go 里用 os.OpenFile 配合 os.O_APPEND | os.O_WRONLY | os.O_CREATE 标志就能安全追加写入,不是用 io.WriteString 或 fmt.Fprintln 就完事——关键在打开文件的方式。
为什么不能直接用 os.Create 或 os.Open 追加?
os.Create 总是清空重写,os.Open 默认只读,二者都不满足“在末尾添加内容”这个核心需求。必须显式控制打开模式:
-
os.O_APPEND:系统保证每次Write都从文件末尾开始(即使有多个 goroutine 同时写,内核会串行化 offset 更新) -
os.O_WRONLY:只写权限,避免误读旧内容干扰逻辑 -
os.O_CREATE:文件不存在时自动创建(但不会覆盖已有文件)
os.OpenFile 的典型调用和常见错误
正确写法:
f, err := os.OpenFile("log.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
_, err = f.WriteString("new line\n")
if err != nil {
log.Printf("write failed: %v", err)
}
容易踩的坑:
立即学习“go语言免费学习笔记(深入)”;
- 漏掉
os.O_WRONLY→ 报错invalid argument(Linux 下 open() 系统调用拒绝只带O_APPEND的只读打开) - 用了
os.O_TRUNC→ 文件被清空,追加变覆盖 - 忘记
defer f.Close()→ 文件句柄泄漏,尤其在循环写日志时很快 hit ulimit - 并发写同一文件但没加锁 → 虽然
O_APPEND保证 offset 安全,但多 goroutine 写短内容仍可能交错(如两行文字挤在同一行),需业务层协调
追加写入性能与缓冲要不要加?
小量写入(比如每秒几条日志)直接用 *os.File 的 WriteString 或 Write 即可;高频写入建议包一层 bufio.Writer:
w := bufio.NewWriter(f)
w.WriteString("entry 1\n")
w.WriteString("entry 2\n")
w.Flush() // 必须显式 flush,否则内容卡在 buffer 里
注意点:
-
bufio.Writer的缓冲区默认 4KB,Flush 前不落盘,程序 panic 或 crash 会导致数据丢失 - 如果要求强持久化(如审计日志),应在
Flush()后调用f.Sync(),但会显著降低吞吐 - 不要对同一个
*os.File同时用未缓冲写和bufio.Writer,buffer 和底层 file offset 可能不同步
真正麻烦的从来不是“怎么追加”,而是“谁在同时写、写完要不要立刻可见、失败了怎么重试、磁盘满了怎么办”——这些得结合具体场景设计,而不是靠一个 O_APPEND 标志解决。










