前言
大家好,我是 倔强青铜三 。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!
欢迎来到 苦练Python第59天!
今天我们要深入的是 tempfile
模块。
它是你写代码时最不想管、但又最离不开的 隐形守护者:
临时文件?自动删。
临时目录?自动清。
多进程并发?安全锁。
学完它,你将彻底告别手动清理 /tmp
、忘记删文件、权限爆炸等 社死现场,用纯 Python 优雅地解决"我的临时文件去哪了"这一灵魂拷问。
🎯 今日收获预览
- 四大高层神器:
TemporaryFile
、NamedTemporaryFile
、TemporaryDirectory
、SpooledTemporaryFile
- 两大底层钉子户:
mkstemp()
、mkdtemp()
- 五大辅助函数:缓存、前缀、目录、字节路径、全局配置
- 实战案例:日志不落盘 、大文件缓存 、单元测试隔离 、多进程锁文件
🧊 热身:为什么不用手撸?
灵魂三问:
- 你敢保证 finally 一定执行?
- 你敢保证 Windows 不掉权限?
- 你敢保证 并发不撞车?
tempfile
全帮你 封装好了 ,还自带 随机文件名 + 权限锁 + 自动清理。
一句话:不要重复造轮子,除非你想起夜删日志。
🗡️ 第一式:无痕临时文件 ------ TemporaryFile
✅ 最简用法
python
import tempfile
with tempfile.TemporaryFile() as fp:
fp.write(b'Hello 青铜三!')
fp.seek(0)
print(fp.read()) # b'Hello 青铜三!'
# 出 with 即灰飞烟灭
🔍 参数拆解
参数 | 说明 | 示例 |
---|---|---|
mode |
默认 w+b ,读写二进制 |
'w+t' 文本模式 |
suffix |
文件名后缀 | '.log' |
prefix |
文件名前缀 | 'myapp_' |
dir |
指定目录 | '/var/tmp' |
💡 坑位提醒
- Unix 下 目录项根本不会出现,Windows 会短暂存在。
- 不要依赖
fp.name
,可能为<fdopen>
。
🗡️ 第二式:具名临时文件 ------ NamedTemporaryFile
✅ 场景
你要把临时文件 传给外部命令 (如 ffmpeg
),需要路径。
python
import tempfile, subprocess
with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp:
tmp.write(b'fake mp4')
name = tmp.name
subprocess.run(['ffprobe', name])
# 用完记得自己 os.unlink(name)
🔍 关键参数
参数 | 说明 | 默认 |
---|---|---|
delete |
关闭时是否删 | True |
delete_on_close |
关闭句柄就删 | True (Win 慎用) |
💡 坑位提醒
- Windows 上如果
delete=True
,别在 with 外再打开。 - 需要二次打开时,设
delete=False
或delete_on_close=False
。
🗡️ 第三式:内存缓冲文件 ------ SpooledTemporaryFile
✅ 场景
小文件放内存,大文件落盘,节省 I/O。
python
from tempfile import SpooledTemporaryFile
with SpooledTemporaryFile(max_size=1024, mode='w+t') as sp:
sp.write('小作文' * 100)
if sp.rolled: # 已落盘?
print('已转储到磁盘')
sp.seek(0)
print(sp.read())
🧠 额外招式
sp.rollover()
手动落盘- 适合 日志缓存 、上传前预处理
🗡️ 第四式:临时目录 ------ TemporaryDirectory
✅ 批量生成临时文件
python
import tempfile, os
with tempfile.TemporaryDirectory(prefix='pytest_') as tmpdir:
path = os.path.join(tmpdir, 'config.json')
open(path, 'w').write('{}')
# 目录下随便造
# 出 with 整个目录被 rm -rf
🔍 参数
参数 | 说明 | 默认 |
---|---|---|
ignore_cleanup_errors |
清理失败是否抛错 | False |
delete |
退出时是否删 | True (调试用 False ) |
🧰 第五式:底层钉子户 ------ mkstemp()
& mkdtemp()
✅ 完全手动,完全控制
python
import tempfile, os
fd, path = tempfile.mkstemp(suffix='.key', text=True)
with os.fdopen(fd, 'w') as f:
f.write('top secret')
os.unlink(path) # 自己删
python
dir_path = tempfile.mkdtemp(prefix='jenkins_')
# 用完自己 shutil.rmtree(dir_path)
💡 坑位提醒
mkstemp
返回 文件描述符 ,别忘os.close(fd)
。- 路径永远 绝对路径(3.12+)。
🔧 辅助函数全家桶
函数 | 用途 | 示例 |
---|---|---|
gettempdir() |
获取系统临时目录 | /tmp |
gettempdirb() |
同上,返回字节 | b'/tmp' |
gettempprefix() |
默认前缀 | 'tmp' |
tempdir |
全局覆盖目录 | tempfile.tempdir = '/opt/tmp' |
🎯 实战 1:日志不落盘
需求:单元测试里打日志,跑完就消失。
python
import logging, tempfile
with tempfile.NamedTemporaryFile(mode='w+t', delete=True) as tmp:
h = logging.FileHandler(tmp.name)
logging.basicConfig(handlers=[h], level=logging.INFO)
logging.info('这条日志没人看得见')
🎯 实战 2:大文件缓存
需求:下载大文件,先放内存,超过 10MB 落盘。
python
from tempfile import SpooledTemporaryFile
import requests
url = 'https://big.file.zip'
with requests.get(url, stream=True) as r, \
SpooledTemporaryFile(max_size=10*1024*1024) as tmp:
for chunk in r.iter_content(8192):
tmp.write(chunk)
tmp.seek(0)
process(tmp) # 传给下游
🎯 实战 3:多进程锁文件
需求:多进程抢资源,用临时目录做锁。
python
import tempfile, os, time, sys
lock_dir = tempfile.mkdtemp(prefix='mylock_')
try:
# 原子创建成功说明抢到锁
lock_file = os.path.join(lock_dir, 'lock')
with open(lock_file, 'x'): # O_EXCL
print('拿到锁,开始干活')
time.sleep(5)
finally:
import shutil
shutil.rmtree(lock_dir)
🧭 常见坑位汇总
场景 | 症状 | 解决 |
---|---|---|
Windows 权限 | PermissionError |
用 delete_on_close=False |
子进程继承句柄 | 文件删不掉 | os.set_inheritable(fd, False) |
全局 tempdir 被改 | 其他库爆炸 | 用 dir= 局部指定 |
字节路径 | TypeError |
全用 b'' 或全用 str |
🧪 今日小结
TemporaryFile
:无痕,最干净。NamedTemporaryFile
:要路径,记得删。SpooledTemporaryFile
:小内存,大落盘。TemporaryDirectory
:整目录,一键清。mkstemp/mkdtemp
:底层 API,完全掌控。- 辅助函数:拿目录、设前缀、改全局。
- 实战三板斧:日志、缓存、锁。
最后感谢阅读!欢迎关注我,微信公众号:
倔强青铜三
。欢迎 点赞、收藏、关注,一键三连!!!