Как удалить файл после `return FileResponse (file_path)`

Я использую FastAPI, чтобы получить изображение, обработать его, а затем вернуть изображение как FileResponse.

Но возвращенный файл является временным, и его необходимо удалить после того, как конечная точка вернет его.

@app.post("/send")
async def send(imagem_base64: str = Form(...)):

    # Convert to a Pillow image
    image = base64_to_image(imagem_base64)

    temp_file = tempfile.mkstemp(suffix = '.jpeg')
    image.save(temp_file, dpi=(600, 600), format='JPEG', subsampling=0, quality=85)

    return FileResponse(temp_file)

    # I need to remove my file after return it
    os.remove(temp_file)

Как я могу удалить файл после его возврата?


person Kleyson Rios    schedule 06.11.2020    source источник


Ответы (2)


Вы можете удалить файл в фоновой задаче, так как она будет запущена после ответ отправлен.

import os
import tempfile

from fastapi import FastAPI
from fastapi.responses import FileResponse

from starlette.background import BackgroundTasks

app = FastAPI()


def remove_file(path: str) -> None:
    os.unlink(path)


@app.post("/send")
async def send(background_tasks: BackgroundTasks):
    fd, path = tempfile.mkstemp(suffix='.txt')
    with os.fdopen(fd, 'w') as f:
        f.write('TEST\n')
    background_tasks.add_task(remove_file, path)
    return FileResponse(path)

Другой подход - использовать зависимость с yield. Код блока finally будет выполняться после отправки ответа и даже после завершения всех фоновых задач.

import os
import tempfile

from fastapi import FastAPI, Depends
from fastapi.responses import FileResponse


app = FastAPI()


def create_temp_file():
    fd, path = tempfile.mkstemp(suffix='.txt')
    with os.fdopen(fd, 'w') as f:
        f.write('TEST\n')
    try:
        yield path
    finally:
        os.unlink(path)


@app.post("/send")
async def send(file_path=Depends(create_temp_file)):
    return FileResponse(file_path)

Примечание. mkstemp () возвращает кортеж с файловым дескриптором и путем.

person alex_noname    schedule 06.11.2020

Возврат StreamingResponse был бы лучшим выбором в вашем случае и был бы более эффективным с точки зрения памяти, поскольку файловая операция блокирует все выполнение вашего цикла событий.

Поскольку вы получаете данные как b64encoded. Вы можете прочитать его как байт и вернуть из него StreamingResponse.

from fastapi.responses import StreamingResponse
from io import BytesIO

@app.post("/send")
async def send(imagem_base64: str = Form(...)):
    in_memory_file = BytesIO()
    image = base64_to_image(imagem_base64)
    image.save(in_memory_file, dpi=(600, 600), format='JPEG', subsampling=0, quality=85)
    in_memory_file.seek(0)
    return StreamingResponse(in_memory_file.read(), media_type="image/jpeg")
person Yagiz Degirmenci    schedule 06.11.2020
comment
Спасибо за совет. - person Kleyson Rios; 09.11.2020
comment
Без проблем! Вам действительно не следует использовать FileResponse в этом случае, IMO. - person Yagiz Degirmenci; 09.11.2020