从Flask下载文件后将其删除 [英] Delete an uploaded file after downloading it from Flask

查看:279
本文介绍了从Flask下载文件后将其删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用一个小型Web界面,该界面允许不同的用户上传文件,转换他们已上传的文件以及下载转换后的文件.转换的详细信息对我的问题并不重要.

I am currently working on a small web interface which allows different users to upload files, convert the files they have uploaded, and download the converted files. The details of the conversion are not important for my question.

我目前正在使用flask-uploads管理上载的文件,并将它们存储在文件系统中.用户上传并转换文件后,会有各种各样漂亮的按钮可以删除该文件,这样上传文件夹就不会被填满.

I am currently using flask-uploads to manage the uploaded files, and I am storing them in the file system. Once a user uploads and converts a file, there are all sorts of pretty buttons to delete the file, so that the uploads folder doesn't fill up.

我认为这不是理想的选择.我真正想要的是在下载文件后立即将其删除.我希望在会话结束时删除要删除的文件.

I don't think this is ideal. What I really want is for the files to be deleted right after they are downloaded. I would settle for the files being deleted when the session ends.

我花了一些时间试图弄清楚该怎么做,但是我还没有成功.看来这并不是一个罕见的问题,所以我认为我必须缺少一些解决方案.有人有解决方案吗?

I've spent some time trying to figure out how to do this, but I have yet to succeed. It doesn't seem like an uncommon problem, so I figure there must be some solution out there that I am missing. Does anyone have a solution?

推荐答案

有几种方法可以做到这一点.

There are several ways to do this.

Flask具有 after_this_request 装饰器,可用于此用途情况:

Flask has an after_this_request decorator which could work for this use case:

@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)

问题在于,这将

The issue is that this will only work on Linux (which lets the file be read even after deletion if there is still an open file pointer to it). It also won't always work (I've heard reports that sometimes send_file won't wind up making the kernel call before the file is already unlinked by Flask). It doesn't tie up the Python process to send the file though.

理想情况下,尽管您已知道将文件清理干净,但操作系统已将其流式传输到客户端.您可以通过创建生成器来将文件流传输回Python来完成此操作,该生成器将文件流传输然后关闭,就像在此答案中建议 :

Ideally though you'd have the file cleaned up after you know the OS has streamed it to the client. You can do this by streaming the file back through Python by creating a generator that streams the file and then closes it, like is suggested in this answer:

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 Web进程,直到将整个文件流式传输到客户端为止.

This approach is nice because it is cross-platform. It isn't a silver bullet however, because it ties up the Python web process until the entire file has been streamed to the client.

在计时器上运行另一个进程(也许使用cron),或使用进程内调度程序,例如 APScheduler 并清理超出超时(例如,在RDMBS中将其标记为下载"后的半小时,一周,三十天)的临时位置的磁盘上的文件

Run another process on a timer (using cron, perhaps) or use an in-process scheduler like APScheduler and clean up files that have been on-disk in the temporary location beyond your timeout (e. g. half an hour, one week, thirty days, after they've been marked "downloaded" in RDMBS)

这是最可靠的方法,但需要额外的复杂性(cron,进程内调度程序,工作队列等)

This is the most robust way, but requires additional complexity (cron, in-process scheduler, work queue, etc.)

这篇关于从Flask下载文件后将其删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆