os.CreateTemp创建的文件不会自动删除,必须显式调用os.Remove清理;测试中应优先使用t.Cleanup注册清理函数,长期服务需结合信号捕获与路径列表统一管理。
Go 语言里没有“用完即焚”的临时文件机制。os.CreateTemp 只负责生成唯一文件名、创建并打开文件,它不绑定任何清理逻辑。你看到的 tmp-12345 文件,只要没被显式删除,就会一直留在磁盘上——哪怕程序已退出、测试已结束、goroutine 已终止。
常见错误现象:本地跑测试时一切正常,CI 环境却反复报磁盘满;服务长期运行后 /tmp 下堆满 backup-*.json;Windows 上删不掉,提示 The process cannot access the file because it is being used by another process。
os.Remove(file.Name()) 或 os.RemoveAll(dir) 才能真正清理defer os.Remove(...) 仅对当前函数有效,且依赖函数正常返回(os.Exit()、panic 时虽仍执行,但 goroutine 内部的 defer 不保证触发)os.Remove:Linux/macOS 通常成功,Windows 直接失败file = nil 后再 defer),会导致 file.Name() panic 或删错路径在 *testing.T 环境下,t.Cleanup 是目前最轻量、最确定的清理入口:它不依赖函数返回,也不怕 panic,只要测试结束(pass/fail/panic),注册的函数就一定执行。
使用场景包括单个文件、整个目录、甚至外部进程资源(如启动的 mock server)。
立即学习“go语言免费学习笔记(深入)”;
t.Cleanup(func() { os.Remove(tmpfile.Name()) })
t.Cleanup(func() { os.RemoveAll(tmpdir) })
t.Cleanup 里调用 t.Fatal 或 t.Error,否则测试框架行为未定义t.TempDir() 替代 os.MkdirTemp:它内部已集成 t.Cleanup,一行搞定目录创建+自动回收命令行工具或 Web 服务一旦调用 os.Exit(),所有 defer 都跳过。协程里写 defer os.RemoveAll 更是无效——进程终止时 goroutine 被强制 kill,defer 根本不执行。
正确做法是把所有临时路径集中登记,用系统信号触发统一清理。
var tempPaths []string
tmp, _ := os.CreateTemp("", "log-*.txt"); tempPaths = append(tempPaths, tmp.Name())
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
for _, p := range tempPaths { os.Remove(p) },注意顺序:先 Close() 再 Remove()
/tmp:它常是 tmpfs,大文件易触发 OOM;建议挂载独立 volume 或改用 /var/tmp
os.RemoveAll 功能强大,但毫无防护意识——传入 "../config.yaml" 就真敢删配置文件。生产环境必须加三道校验。
absPath, _ := filepath.Abs(dir)
strings.HasPrefix(absPath, os.TempDir()+string(os.PathSeparator))
if absPath == "/" || strings.HasSuffix(absPath, "/home") || strings.HasSuffix(absPath, "/Users")
os.Chmod(path, 0644) 再重试 2 次,每次 time.Sleep(100 * time.Millisecond)
errors.Is(err, fs.ErrNotExist) 或 errors.Is(err, syscall.ENOTEMPTY)
实际写法里最容易漏掉的是路径校验和 Windows 文件锁处理。很多团队只在 Linux 测试通过就上线,结果 Windows 服务跑几天后临时目录越积越多,最后发现是 os.RemoveAll 静默失败了。