tempfile.TemporaryDirectory清理触发PermissionError与NotADirectoryError问题
PDF转图片后临时目录清理失败(PermissionError/NotADirectoryError)
问题场景
使用pdf2image结合poppler将PDF转图片时,通过tempfile.TemporaryDirectory()管理转换生成的临时文件,转换完成保存目标图片后,程序崩溃并抛出PermissionError(文件被占用)和后续的NotADirectoryError(误将文件当目录处理)。
原代码:
with tempfile.TemporaryDirectory() as path: images_from_path: [Image] = convert_from_path( os.path.join(path_superfolder, "calibration_target.pdf"), size=(2480, 3508), output_folder=path, poppler_path=r'E:\poppler-22.04.0\Library\bin') if len(images_from_path) >= page: images_from_path[page - 1].save(os.path.join(path_superfolder, "result.jpg"))
错误栈核心:
PermissionError: [WinError 32] The process cannot access the file, because it is being used by another process: 'xxx.ppm' ... NotADirectoryError: [WinError 267] Directory name invalid: 'xxx.ppm'
解决方案
方案1:避免生成本地临时文件(推荐,代码更简洁)
不指定output_folder,让convert_from_path直接在内存中生成Image对象,无需创建本地临时文件,从根源上避免文件占用问题。
修改后代码:
from pdf2image import convert_from_path import os images_from_path = convert_from_path( os.path.join(path_superfolder, "calibration_target.pdf"), size=(2480, 3508), poppler_path=r'E:\poppler-22.04.0\Library\bin' ) if len(images_from_path) >= page: images_from_path[page - 1].save(os.path.join(path_superfolder, "result.jpg"))
方案2:手动关闭Image句柄+延迟清理
如果必须使用output_folder(比如PDF过大,内存处理压力大),手动关闭所有Image对象的文件句柄,确保释放文件锁,Windows下可增加短暂延迟保证poppler进程完全退出。
修改后代码:
import tempfile import os import time from pdf2image import convert_from_path with tempfile.TemporaryDirectory() as path: images_from_path = convert_from_path( os.path.join(path_superfolder, "calibration_target.pdf"), size=(2480, 3508), output_folder=path, poppler_path=r'E:\poppler-22.04.0\Library\bin' ) if len(images_from_path) >= page: images_from_path[page - 1].save(os.path.join(path_superfolder, "result.jpg")) # 关闭所有Image对象的文件句柄,释放文件锁 for img in images_from_path: img.close() # Windows下可选:短暂延迟,确保poppler子进程完全释放文件 time.sleep(0.1)
方案3:手动管理临时目录,逐个删除文件
放弃TemporaryDirectory的自动清理,手动创建临时目录,先逐个删除文件再删除目录,绕过rmtree的错误处理缺陷。
修改后代码:
import tempfile import os import shutil from pdf2image import convert_from_path # 手动创建临时目录 tmp_path = tempfile.mkdtemp() try: images_from_path = convert_from_path( os.path.join(path_superfolder, "calibration_target.pdf"), size=(2480, 3508), output_folder=tmp_path, poppler_path=r'E:\poppler-22.04.0\Library\bin' ) if len(images_from_path) >= page: images_from_path[page - 1].save(os.path.join(path_superfolder, "result.jpg")) # 关闭所有Image句柄 for img in images_from_path: img.close() # 逐个删除临时文件 for file_name in os.listdir(tmp_path): file_path = os.path.join(tmp_path, file_name) if os.path.isfile(file_path): try: os.unlink(file_path) except Exception as e: print(f"删除临时文件失败: {e}") # 删除空目录 os.rmdir(tmp_path) except Exception as e: print(f"处理流程出错: {e}") # 出错时强制清理临时目录 try: shutil.rmtree(tmp_path, ignore_errors=True) except: pass
原因分析
- 文件锁占用:Windows系统文件锁机制严格,
convert_from_path生成的PPM文件可能被PIL的Image对象持有未关闭的句柄,或者poppler的转换子进程未完全退出,导致临时目录清理时无法删除文件,触发PermissionError。 - rmtree错误处理缺陷:
shutil.rmtree在处理删除文件失败的错误时,错误地将文件路径当作目录进行递归删除操作,进而引发NotADirectoryError。
内容的提问来源于stack exchange,提问作者Liqs
相关产品推荐
相关产品推荐

