Delete downloaded file after downloading it from Flask

I am currently working on a small web interface that allows other users to upload files, convert the files that they download, and download the converted files. The conversion details are not important to my question.

I am currently using fly uploads to manage downloaded files and I store them in the file system. When the user downloads and converts the file, there are all kinds of beautiful buttons for deleting the file, so the uploads folder is not filled.

I do not think this is perfect. I really want the files to be deleted right after they are downloaded. I agree to delete the files at the end of the session.

I spent some time trying to figure out how to do this, but I still have to succeed. This does not seem like an unusual problem, so I believe that there should be some solution that I am missing. Anyone have a solution?

+13
python flask flask-uploads
source share
1 answer

There are several ways to do this.

send_file and then delete it immediately (Linux only)

Flask has an after_this_request decorator that can work for this after_this_request use:

 @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 problem is that this will only work on Linux (which allows you to read the file even after deletion if it still has an open file pointer to it). This also does not always work (I heard reports that sometimes send_file did not send_file a kernel call before Flask already detached the file). This does not bind the Python process to send the file, though.

Stream file then delete

Ideally, at least the file should be cleaned after you find out that the OS passed it to the client. You can do this by streaming the file back through Python by creating a generator that translates the file and then closes it, as 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} ) 

This approach is good because it is cross-platform. However, this is not a silver bullet because it binds the Python web process until the entire file is transferred to the client.

Get out of the timer

Start another timer process (possibly using cron ) or use an in- process scheduler such as APScheduler and clear the files that were on disk at a temporary location outside of your waiting time (for example, half an hour, one week, thirty days after of how they were marked as "loaded" in RDMBS)

This is the most reliable way, but it requires additional complexity (cron, scheduler in progress, work queue, etc.)

+26
source share

All Articles