Go中追加写入需用os.OpenFile配os.O_APPEND|os.O_WRONLY|os.O_CREATE标志,或Go1.16+的os.AppendFile;禁用os.O_TRUNC,注意并发安全与Sync需求。

用 os.OpenFile 以 os.O_APPEND 模式追加写入
Go 中没有单独的 “append” 函数,必须用 os.OpenFile 手动指定标志位。直接调用 os.AppendFile(Go 1.16+)最简,但底层仍是 os.OpenFile + os.O_APPEND。关键点在于:不加 os.O_CREATE 时,文件不存在会报错;加了则自动创建。
常见错误是误用 os.Create 或 os.OpenFile 未带 os.O_APPEND,导致覆盖而非追加。
-
os.OpenFile("log.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)是安全追加的标准写法 - 如果只写
os.O_APPEND不加os.O_CREATE,文件不存在会返回"no such file or directory" - 权限参数
0644在文件新建时生效,已存在文件不受影响
os.AppendFile 是最简追加方式(Go 1.16+)
如果你用的是 Go 1.16 或更新版本,os.AppendFile 就是专为追加设计的封装函数,一行搞定,内部已处理创建、打开、写入、关闭全流程。
它比手写 OpenFile 更少出错,尤其适合日志、临时记录等场景。但注意:它每次调用都会重新打开/关闭文件,高频小写入(如每毫秒一条日志)会有性能开销,此时应复用 *os.File 句柄。
err := os.AppendFile("data.txt", []byte("new line\n"))
if err != nil {
log.Fatal(err)
}
写入时避免覆盖:别误用 os.Create 或 os.O_TRUNC
os.Create 等价于 os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) —— 关键是 os.O_TRUNC,它会让文件内容被清空。这是追加场景下最常见的误操作。
同样,手动调用 os.OpenFile 时若混入 os.O_TRUNC,哪怕同时写了 os.O_APPEND,行为也是未定义的(实际多数系统会忽略 APPEND,直接截断)。
- 永远不要在追加逻辑里出现
os.O_TRUNC -
os.Create只适用于“从头写新文件”,不是“追加”的替代方案 - 检查错误时注意:
"invalid argument"有时就是标志位冲突(如O_APPEND | O_TRUNC)
追加写入后是否需要手动 Sync?
一般不需要。Go 的 Write 默认走内核页缓存,操作系统会在合适时机刷盘。但如果你写的是关键日志(如支付成功记录),且要求“写入即落盘”,就得显式调用 file.Sync()。
注意:os.AppendFile 不提供同步选项;若需 Sync,必须用 os.OpenFile 获取 *os.File,写完再调用 Sync。另外,Sync 是阻塞操作,频繁调用会显著拖慢性能。
f, err := os.OpenFile("audit.log", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
if err != nil {
log.Fatal(err)
}
defer f.Close()
_, err = f.Write([]byte("operation: delete user\n"))
if err != nil {
log.Fatal(err)
}
err = f.Sync() // 关键:确保立即写入磁盘
if err != nil {
log.Fatal(err)
}
追加写入真正容易被忽略的,是并发写同一文件时的竞态——Go 标准库不保证多 goroutine 对同一 *os.File 的写入顺序或原子性。如果多个地方同时往一个文件追加,得自己加锁,或者改用日志库(如 zap)来处理同步。










