os.WriteFile 无法写入文件头部,因其总是覆盖整个文件;需插入头部时须读取全量、拼接新内容、再覆盖写回,适用于中小文件。

为什么不能直接用 os.WriteFile 写入文件头部
因为 os.WriteFile 总是覆盖整个文件,无法在开头插入数据而不影响原有内容。真实场景中,比如向日志文件前追加时间戳头、给二进制文件写 magic number、或在 JSON 文件前加 BOM,都需要「把新数据塞到最前面,原内容往后移」——这本质是「插入」操作,而文件系统不支持随机位置插入。
标准做法:读全量 + 拼接 + 覆盖写回
这是最稳妥、跨平台、无需第三方库的方式。适用于中小文件(
- 用
os.ReadFile一次性读取原文件全部内容 - 将头部数据(
[]byte)和原内容拼成新切片:append(header, content...) - 用
os.WriteFile全量写回同一路径
示例:
header := []byte("# Generated at 2024-06-15\n")
content, err := os.ReadFile("config.txt")
if err != nil {
log.Fatal(err)
}
newContent := append(header, content...)
err = os.WriteFile("config.txt", newContent, 0644)
if err != nil {
log.Fatal(err)
}大文件怎么办?用 os.OpenFile + io.Copy 流式处理
当文件太大(如几百 MB 日志),全量读入内存会 OOM。此时需流式处理,但注意:必须借助临时文件,因为无法原地扩展文件开头。
立即学习“go语言免费学习笔记(深入)”;
- 用
os.CreateTemp创建临时文件 - 先写入 header,再用
io.Copy把原文件内容流式拷贝过去 - 用
os.Rename原子替换原文件(Linux/macOS 安全;Windows 需确保同盘符)
关键点:不要用 os.OpenFile(..., os.O_WRONLY|os.O_CREATE) 直接打开原文件写——那只会覆盖,不是插入。
容易被忽略的边界情况
实际部署时这几个点常出问题:
- 原文件不存在?
os.ReadFile会报os.IsNotExist(err),需单独处理(比如先创建空文件再写 header) - 权限不足导致写回失败?检查目标路径是否可写,尤其在 Docker 容器或 systemd 服务里,工作目录可能只读
- 并发写入冲突?如果多个 goroutine 同时执行该逻辑,必须加
sync.Mutex或用文件锁(syscall.Flock)保护 - header 含非 UTF-8 字节(如 PNG 头)?确保用
[]byte操作,别误转成string再拼接,避免编码截断
真正难的不是写几行代码,而是想清楚「谁在什么时候可能同时碰这个文件」以及「磁盘满没满、权限对不对」——这些往往比 Go 语法更早暴露问题。


















