You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

原因分析

  1. 文件锁占用:Windows系统文件锁机制严格,convert_from_path生成的PPM文件可能被PIL的Image对象持有未关闭的句柄,或者poppler的转换子进程未完全退出,导致临时目录清理时无法删除文件,触发PermissionError。
  2. rmtree错误处理缺陷:shutil.rmtree在处理删除文件失败的错误时,错误地将文件路径当作目录进行递归删除操作,进而引发NotADirectoryError。

内容的提问来源于stack exchange,提问作者Liqs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 09:40:30