Ответ 1
Есть несколько способов сделать это.
send_file
а затем сразу же удалить (только для Linux)
Flask имеет декоратор after_this_request
который может работать для этого after_this_request
использования:
@app.route('/files/<filename>/download')
def download_file(filename):
file_path = derive_filepath_from_filename(filename)
file_handle = open(file_path, 'r')
@after_this_request
def remove_file(response):
try:
os.remove(file_path)
file_handle.close()
except Exception as error:
app.logger.error("Error removing or closing downloaded file handle", error)
return response
return send_file(file_handle)
Проблема заключается в том, что это будет работать только в Linux (что позволяет читать файл даже после удаления, если на него все еще есть открытый указатель файла). Это также не всегда работает (я слышал сообщения о том, что иногда send_file
не send_file
вызов ядра до того, как Flask уже отсоединит файл). Это не связывает процесс Python для отправки файла, хотя.
Потоковый файл, затем удалите
В идеале, хотя бы файл должен быть очищен после того, как вы узнаете, что ОС передала его клиенту. Вы можете сделать это путем потоковой передачи файла обратно через Python, создав генератор, который транслирует файл и затем закрывает его, как предлагается в этом ответе:
def download_file(filename):
file_path = derive_filepath_from_filename(filename)
file_handle = open(file_path, 'r')
# This *replaces* the 'remove_file' + @after_this_request code above
def stream_and_remove_file():
yield from file_handle
file_handle.close()
os.remove(file_path)
return current_app.response_class(
stream_and_remove_file(),
headers={'Content-Disposition': 'attachment', 'filename': filename}
)
Этот подход хорош, потому что он кроссплатформенный. Однако это не серебряная пуля, потому что он связывает веб-процесс Python до тех пор, пока весь файл не будет передан клиенту.
Убирайся по таймеру
Запустите другой процесс по таймеру (возможно, с использованием cron
) или используйте внутрипроцессный планировщик, такой как APScheduler, и очистите файлы, которые были на диске, во временном местоположении за пределами вашего времени ожидания (например, полчаса, одна неделя, тридцать дней, после того, как они были помечены как "загруженные" в RDMBS)
Это самый надежный способ, но он требует дополнительной сложности (cron, планировщик в процессе, рабочая очередь и т.д.)