os.CreateTemp是创建临时文件的唯一安全方式,需检查创建和关闭错误,写入后手动删除,大文件应使用bufio.NewWriter或io.Copy优化性能。

用 os.CreateTemp 创建临时文件再写入
Go 标准库不提供“直接向临时文件写数据”的单步函数,必须先创建临时文件,再调用 Write 或 WriteString。关键在于:别用 os.TempDir() 拼路径手动 os.Create,容易出竞态或权限问题——os.CreateTemp 才是唯一安全方式。
常见错误现象:open /tmp/myfile: permission denied(目录不可写)、no such file or directory(父目录不存在)、或多个 goroutine 同时调用导致文件名冲突。
-
os.CreateTemp(dir, pattern)的dir可为"",此时自动使用os.TempDir() -
pattern中至少含一个"*",如"data-*.txt",替换后保证唯一性 - 返回的
*os.File默认可读写,无需额外os.O_RDWR标志 - 务必检查
err,创建失败时文件句柄为nil,直接写会 panic
写入后记得关闭文件并处理错误
临时文件不是“写完就完”,Write 可能成功但 Close 失败(比如磁盘满、只读文件系统),而 Close 才真正刷盘并释放资源。忽略 Close 错误会导致数据丢失却不报错。
典型场景:生成配置片段、缓存二进制中间结果、单元测试中模拟输入文件。
- 用
defer f.Close()不够——它只延迟执行,不捕获错误;应显式检查f.Close()返回的err - 若需原子性(防止写到一半被读),先写入临时路径,再
os.Rename覆盖目标(仅限同目录) - 避免在循环里反复创建/关闭临时文件,性能差且可能耗尽文件描述符
f, err := os.CreateTemp("", "log-*.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close() // 仅延迟关闭,不处理错误
_, err = f.WriteString("hello\n")
if err != nil {
log.Fatal(err)
}
err = f.Close() // 必须再检查一次
if err != nil {
log.Fatal(err) // 磁盘满等场景在此暴露
}
临时文件没被自动清理,得自己删
Go 不会在进程退出或文件关闭时自动删除临时文件,这是设计使然——你创建的文件就是普通文件,生命周期由你控制。不删就会堆积在 /tmp 或指定目录,尤其服务长期运行时容易占满磁盘。
容易踩的坑:defer os.Remove(f.Name()) 看似合理,但若 f.Name() 在 Close() 前被其他进程重命名或删除,会静默失败;更糟的是,如果写入中途 panic,defer 可能根本没执行。
- 推荐策略:写完即删,且确保
Remove在Close()之后调用 - 若需保留临时文件供后续使用(如子进程读取),明确记录路径并安排超时清理逻辑
- 测试中可用
t.Cleanup(func(){ os.Remove(f.Name()) })(t *testing.T)保证收尾
大文件写入要考虑缓冲和内存占用
直接对 *os.File 调用 Write 是无缓冲的系统调用,小数据没问题;但写几百 MB 的临时文件时,频繁 syscall 会拖慢速度,且若一次性 Write([]byte{...}) 构造大切片,会吃光内存。
适用场景:导出日志快照、压缩前暂存原始数据、AI 推理中间特征文件。
- 用
bufio.NewWriter(f)包一层,WriteString后调Flush(),减少 syscall 次数 - 避免
bytes.Buffer先拼接再写——它把所有内容存内存,失去流式优势 - 若数据来自网络或磁盘,用
io.Copy直接从Reader流式写入*os.File,零内存拷贝
临时文件路径本身不是秘密,但内容可能敏感;os.CreateTemp 默认权限是 0600(仅属主可读写),这点不用额外 chmod——除非你改了 umask 或显式调了 Chmod。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











