tempfile模块默认不自动删除临时文件,namedtemporaryfile需设delete=false并手动unlink,temporarydirectory退出with块时自动递归删除,mktemp已弃用。

临时文件删不掉?tempfile 默认行为不等于“用完即焚”
python 的 tempfile 模块默认创建的临时文件,**不会在对象销毁时自动删除**——这是最常被误读的一点。很多人以为 NamedTemporaryFile 或 mktemp 返回的文件句柄一出作用域就消失,结果发现磁盘上残留一堆 /tmp/tmpxxxxxx 文件。
关键原因:只有显式设置了 delete=True(默认值),且未调用 .close() 前就离开上下文,才可能自动清理;但一旦手动 .close(),哪怕在 with 块里,delete=True 也会立即触发删除——这反而导致后续无法读取。
-
NamedTemporaryFile(delete=False)是安全读写+手动清理的标配,用完必须自己调os.unlink(filepath) -
TemporaryDirectory()是目录级方案,退出with块时自动递归删除整个目录,比拼接路径再rmtree更可靠 - 避免用
mktemp():它只返回路径字符串,不创建文件,也不管理生命周期,极易引发竞态条件和权限问题
TemporaryDirectory 为什么比手建 /tmp/myapp_$$ 更稳
手动生成带时间戳或 PID 的临时目录名看似简单,但实际踩坑密集:路径冲突、权限不足、清理遗漏、符号链接绕过 rmtree 等。
TemporaryDirectory 内部调用 mkdtemp(),确保原子性创建,并把路径绑定到对象生命周期上。退出 with 块时,它会强制执行 shutil.rmtree(),且对 windows 的只读文件有兼容处理(先改权限再删)。
立即学习“Python免费学习笔记(深入)”;
- 不要试图在
TemporaryDirectory创建后修改其name属性——它只是个普通字符串,改了不影响实际目录,还可能误导清理逻辑 - 若需子目录,直接
os.path.join(temp_dir.name, "sub")+os.makedirs(),别重复 new 一个TemporaryDirectory - 跨进程共享该目录?不行。它的生命周期只绑定当前 Python 进程的上下文管理器,子进程得靠传路径+约定清理责任
Windows 下 NamedTemporaryFile 打开失败的真正原因
错误信息通常是:PermissionError: [WinError 32] The process cannot access the file because it is being used by another process。
根本不是权限设置问题,而是 Windows 锁定文件策略:只要 NamedTemporaryFile 以默认方式(delete=True)创建,文件句柄打开时就已独占锁定,其他进程(甚至同一进程的另一线程)无法以读模式再次打开它——而 linux 允许。
- 解决方案只有两个:
delete=False+ 手动管理,或改用tempfile.mkstemp()(返回(fd, path),可自行控制os.close(fd)和文件访问时机) -
mkstemp()创建的文件默认权限是0o600,Linux/macos 下没问题,但 Windows 忽略该权限位,所以无需额外chmod - 别用
open(tempfile.mktemp(), "w"):它不保证路径唯一,mktemp()已被标记为 deprecated
测试中反复创建临时资源,怎么避免“Too many open files”
高频调用 NamedTemporaryFile 或 TemporaryDirectory 而没及时释放,会导致文件描述符耗尽,尤其在 CI 环境或容器里限制更严。
核心矛盾在于:TemporaryDirectory 的 __exit__ 会等 rmtree 完成才返回,而 rmtree 在大量小文件时可能慢;NamedTemporaryFile 若没进 with 块,对象被 gc 回收前文件句柄一直挂着。
- 单元测试里优先用
unittest.mock.patch("tempfile.mkdtemp", return_value="/fake/path")隔离真实 I/O - 真要跑实测,把临时资源创建提到类级
setUpClass,统一清理放在tearDownClass,而不是每个 test 方法都 new 一个 - 检查是否无意中在循环里调用了
TemporaryDirectory()却没close()—— 它没有close()方法,但__exit__必须触发,否则目录残留且 fd 不释放
临时资源真正的复杂点不在创建,而在“谁负责删、什么时候删、删之前能不能被别的逻辑访问”。Python 不替你做决策,只提供不同粒度的工具;选错那个“默认值”,后面就得花三倍时间补救。