2

I am having an issue trying to download download in-memory ZIP-FILE object using Flask send_file. my zip exists in memory and is full of text documents but when I try with this code the result I get is: it downloads like it is supposed to but it downloads an empty zip file! it's like it is copying nothing ... I have no idea how to solve this problem.

 @app.route('/downloads/', methods=['GET'])
    def download():
        from flask import send_file
        import io
        import zipfile
        import time
        FILEPATH = r"C:\Users\JD\Downloads\trydownload.zip"
        fileobj = io.BytesIO()
        with zipfile.ZipFile(fileobj, 'w') as zip_file:
            zip_info = zipfile.ZipInfo(FILEPATH)
            zip_info.date_time = time.localtime(time.time())[:6]
            zip_info.compress_type = zipfile.ZIP_DEFLATED
            with open(FILEPATH, 'rb') as fd:
                zip_file.writestr(zip_info, fd.read())
        fileobj.seek(0)
    
        return send_file(fileobj, mimetype='zip', as_attachment=True,
                         attachment_filename='%s.zip' % os.path.basename(FILEPATH))
Josh.h
  • 71
  • 1
  • 13
  • this code works for me on Linux. But it gives `trydownload.zip` inside `trydownload.zip.zip`. And inner file has full path - `/home/furas/test/trydownload.zip` - so when I uncompress it then it creates these folders in current folder - `current_folder/home/furas/test/trydownload.zip` – furas Jun 01 '21 at 09:20
  • it does work on windows. when i was opening it directly it looked empty but when extracting it i see the file. my fault. do you have any idea how to get the zip directly, and not a "zip of the zip"? – Josh.h Jun 01 '21 at 09:26
  • if you want to send `C:\Users\JD\Downloads\trydownload.zip` then send it directly - `send_file(r"C:\Users\JD\Downloads\trydownload.zip")` – furas Jun 01 '21 at 09:27
  • do you mean without going through the fileobj = io.BytesIO() ? i thought the zip had to be treated as Bytes – Josh.h Jun 01 '21 at 09:28
  • `io.BytesIO()` can be useful only if you would read ie. text file and you want to convert it to zip file without writing on disk - but you already have zip file on disk. You don't need it if you want to send file from disk. – furas Jun 01 '21 at 09:30
  • ok. thank you for your constructive remarks!! – Josh.h Jun 01 '21 at 09:33
  • @Josh.h - did you manage to solve this issue? I'm facing a similar issue. I've integrated my code with swagger documentation and I'm getting an `Undocumented Error: OK`. And I'm getting an empty zip file as well although I have verified that the ZipFile object has valid files in it. – Rahul P Jul 12 '21 at 21:49

1 Answers1

3

I had the exact same issue with the Flask send_file method.

Details:
Flask version 2.0.1
OS: Windows 10

Solution
I figured out a workaround to this i.e. instead of the send_file method, this can be done by returning a Response object with the data. Replace the return statement in your code with the following and this should work.

@app.route('/downloads/', methods=['GET'])
    def download():
        from flask import Response # Changed line
        import io
        import zipfile
        import time
        FILEPATH = r"C:\Users\JD\Downloads\trydownload.zip"
        fileobj = io.BytesIO()
        with zipfile.ZipFile(fileobj, 'w') as zip_file:
            zip_info = zipfile.ZipInfo(FILEPATH)
            zip_info.date_time = time.localtime(time.time())[:6]
            zip_info.compress_type = zipfile.ZIP_DEFLATED
            with open(FILEPATH, 'rb') as fd:
                zip_file.writestr(zip_info, fd.read())
        fileobj.seek(0)

        # Changed line below
        return Response(fileobj.getvalue(),
                        mimetype='application/zip',
                        headers={'Content-Disposition': 'attachment;filename=your_filename.zip'})
Rahul P
  • 2,493
  • 2
  • 17
  • 31