为什么临时/文件目录在从“with”块返回之前而不是之后被删除?

问题描述 投票:0回答:2

我正在尝试返回一个使用

openpyxl
FastAPI
从模板修改的 excel 文件(类型可能不相关),但我得到了
File at path C:\\Users\\user\\AppData\\Local\\Temp\\tmpg3am6f8d\\1050669-export.xlsx does not exist.

如果我转到临时文件夹,我可以看到临时目录出现(文件也在那里),但它们在执行 return 语句之前被删除。如果我在返回语句之前

print(os.path.exists(path))
,我会得到
True

with TemporaryDirectory() as tmp:
    path = os.path.join(tmp, id + "-export.xlsx")
    wb.save(path)

    return FileResponse(path)

有没有办法防止在 return 语句之前开始删除目录/文件?或者我应该采取其他方式吗?

python fastapi openpyxl temporary-files
2个回答
0
投票

您在

tempfile.TemporaryFile
块中使用
with
。这意味着当您的代码退出
with
上下文时,临时文件将被删除。这正是当您从函数中
return
时发生的情况,这就是为什么在 FastAPI 能够访问文件之前文件被删除的原因。换句话说,该行为正是您所要求的。

解决此问题的一种方法是使用

StreamingResponse
而不是
FileResponse
。也许是这样的:

from tempfile import TemporaryFile

from fastapi import FastAPI
from fastapi.responses import StreamingResponse

app = FastAPI()

async def temporaryFileGenerator():
    with TemporaryFile() as fd:
        fd.write('This is a test\n'.encode())
        fd.seek(0)

        while True:
            data = fd.read(1024)
            if not data:
                break

            yield data

@app.get('/example1')
async def example1():
    return StreamingResponse(temporaryFileGenerator())

因为我们正在流式传输文件,而不是简单地返回文件名,所以在我们将所有字节流式传输到客户端之前,

with
块不会退出。


0
投票

根据文档

TemporaryDirectory()
将在上下文结束之前删除该目录。

考虑到您的工作流程,您应该使用

mkdtemp()
函数,请记住您必须处理 删除操作。我创建了一个示例,请随意遵循

import os
from tempfile import mkdtemp, TemporaryDirectory


def define_temporal_and_ephemeral_dir() -> str:
    with TemporaryDirectory() as tmp:
        return tmp

def define_temporal_dir() -> str:
    tmp = mkdtemp()

    return tmp


if __name__ == '__main__':

    # Ephemeral directory logic.
    ephemeral_path = define_temporal_and_ephemeral_dir()

    is_dir_exists = os.path.exists(ephemeral_path)
    print(f'{ephemeral_path} exists: {is_dir_exists}\n')

    assert is_dir_exists == False

    # Non ephemeral directory logic.
    path = define_temporal_dir()

    is_dir_exists = os.path.exists(path)
    print(f'{path} exists: {is_dir_exists}\n')

    assert is_dir_exists == True

    # The user has to be responsible to manually remove the temporal directory created.
    os.rmdir(path)
    is_dir_exists = os.path.exists(path)

    assert is_dir_exists == False

    print('Non ephemeral directory was removed.')

免责声明:我在Mac上测试了这个,希望你在Windows环境上测试时不会发现问题。

输出

/var/folders/dm/z6w7zmj1193gcb_n0v5p04jw0000gn/T/tmp974g8vpb exists: False

/var/folders/dm/z6w7zmj1193gcb_n0v5p04jw0000gn/T/tmpbujzyodz exists: True

Non ephemeral directory was removed.
© www.soinside.com 2019 - 2024. All rights reserved.