我目前正在开发一个小型网络界面,允许不同的用户上传文件,转换他们上传的文件,并下载转换后的文件。转换的详细信息对我的问题并不重要。
我目前正在使用flask-uploads来管理上传的文件,我将它们存储在文件系统中。一旦用户上传并转换文件,就会有各种漂亮的按钮来删除文件,因此上传文件夹不会填满。
我不认为这是理想的。我真正想要的是在下载文件后立即删除它们。我会满足会议结束时被删除的文件。
我花了一些时间试图弄清楚如何做到这一点,但我还没有成功。这似乎不是一个不寻常的问题,所以我认为必须有一些解决方案,我错过了。有没有人有解决方案?
答案 0 :(得分:23)
Flask有一个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)
问题是这将only work well on Linux(如果仍然有一个打开的文件指针,即使在删除后也可以读取文件)。
答案 1 :(得分:1)
您还可以将文件存储在内存中,将其删除,然后提供您在内存中的存储空间。
例如,如果您正在提供PDF:
var yourThing = new Thing()
.with(new PropertyA()).thenWith(new DependentPropertyOfA()) // digress a bit
.with(new PropertyB()) // back to main thread here
.withPieceOfLogic((parameter1, parameter2) => {define some logic here}) // so you can potentially can swap implementations as well
.create();
(上面我只是假设它是PDF,但是如果需要,您可以get the mimetype以编程方式进行操作)
答案 2 :(得分:0)
基于@Garrett的注释,更好的方法是在删除文件时不阻止send_file
。恕我直言,更好的方法是在后台将其删除,如下所示更好:
import io
import os
from flask import send_file
from multiprocessing import Process
@app.route('/download')
def download_file():
file_path = get_path_to_your_file()
return_data = io.BytesIO()
with open(file_path, 'rb') as fo:
return_data.write(fo.read())
return_data.seek(0)
background_remove(file_path)
return send_file(return_data, mimetype='application/pdf',
attachment_filename='download_filename.pdf')
def background_remove(path):
task = Process(target=rm(path))
task.start()
def rm(path):
os.remove(path)
答案 3 :(得分:0)
Flask 有一个 after_request 装饰器,可以在这种情况下工作:
@app.route('/', methods=['POST'])
def upload_file():
uploaded_file = request.files['file']
file = secure_filename(uploaded_file.filename)
@app.after_request
def delete(response):
os.remove(file_path)
return response
return send_file(file_path, as_attachment=True, environ=request.environ)