7

here's my function that creates file on the fly(when the user clicks proper link)

@app.route('/survey/<survey_id>/report')
def survey_downloadreport(survey_id):
    survey, bsonobj = survey_get(survey_id) #get object
    resps = response_get_multi(survey_id) #get responses to the object

    fields = ["_id", "sid", "date", "user_ip"] #meta-fields
    fields.extend(survey.formfields) #survey-specific fields

    randname = "".join(random.sample(string.letters + string.digits, 15)) + ".csv" #some random file name

    with open("static//" + randname, "wb") as csvf:
        wr = csv.DictWriter(csvf, fields, encoding = 'cp949')
        wr.writerow(dict(zip(fields, fields))) #dummy, to explain what each column means
        for resp in resps :
            wr.writerow(resp)

    return send_from_directory("static", randname, as_attachment = True)

I'd like to have file to be deleted after completing of the download. How can I do it?

thkang
  • 11,215
  • 14
  • 67
  • 83

2 Answers2

7

On Linux, if you have an open file you can still read it even when deleted. Do this:

import tempfile
from flask import send_file

csvf = tempfile.TemporaryFile()
wr = csv.DictWriter(csvf, fields, encoding = 'cp949')
wr.writerow(dict(zip(fields, fields))) #dummy, to explain what each column means
for resp in resps :
    wr.writerow(resp)
wr.close()
csvf.seek(0)  # rewind to the start

send_file(csvf, as_attachment=True, attachment_filename='survey.csv')

The csvf file is deleted as soon as it is created; the OS will reclaim the space once the file is closed (which cpython will do for you as soon as the request is completed and the last reference to the file object is deleted). Optionally, you could use the after_this_request hook to explicitly close the file object.

Avinash Raj
  • 172,303
  • 28
  • 230
  • 274
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    This feature gave us a hard time some time ago. Our mailserver was unlinking files without closing the file descriptors. Suddenly the system reported `disk full` but `df` was showing plenty of disk space. Use with caution - it can be really hard to find such bug. – bikeshedder Jan 30 '13 at 22:26
  • @bikeshedder: check for open file descriptors next time :-) It's a common enough pattern. – Martijn Pieters Jan 30 '13 at 22:28
  • To the suggested edit: note the `attachment_filename` argument used for `send_file()`; it provides the filename to be used, not the temporary file. There is absolutely no need to use a `NamedTemporaryFile` here. – Martijn Pieters Jan 23 '15 at 11:29
  • @Martijn Pieters How do I check for open file descriptors next time? – Ishan Bhatt Jul 28 '16 at 10:18
-1

I've used os.unlink for a while with success:

import os

os.unlink(os.path.join('/path/files/csv/', '%s' % file))

Hope it helps.

mjpirez
  • 7
  • 1