pythondjangozipzipstream

Getting corrupt zips using Python ZipStream in Django


I am a little new to Django so please bear with me.
I'm using zipstream from here and have a Django view that returns a zip file of all file attachments which are all hosted on Amazon S3. But the zip files are all coming up as corrupt when I download them, that is, I can't open them. I have tried verifying the files with unzip -t but the errors are not very helpful.

file_paths = [fa.file.url for fa in file_attachments.all()]

zf = zipstream.ZipFile(mode='w', compression=zipstream.ZIP_DEFLATED)

zip_subdir = "Attachments-%s" % (request_id)

for file_path in file_paths:
    file_dir, file_name = os.path.split(file_path)

    zf.writestr(file_name, urllib.urlopen(file_path).read())

zip_filename = "%s.zip" % (zip_subdir)

response = StreamingHttpResponse(zf, mimetype='application/zip')
response['Content-Disposition'] = \
    'attachment; filename={}'.format(zip_filename)
return response

Any ideas?

Solved it.

s = StringIO.StringIO()
with zipstream.ZipFile(s, mode='w', compression=zipstream.ZIP_DEFLATED) as zf:
    #could fail on url open.
    for file_path in file_paths:
        file_dir, file_name = os.path.split(file_path)

        try:
            file_contents = urllib.urlopen(file_path).read()
            zf.writestr(file_name, file_contents)
        except IOError: #connection cannot be made
            logging.error()

response = StreamingHttpResponse(s.getvalue(), mimetype='application/octet-stream')
response['Content-Disposition'] = \
    'attachment; filename={}'.format("%s" % (request_id))
return response

Solution

  • You should close the ZipFile when you're done writing to it. Otherwise, to quote the documentation, "essential records will not be written" until you do.

    The cleanest way to do it is using the with statement:

    with zipstream.ZipFile(mode='w', compression=zipstream.ZIP_DEFLATED) as zf:
        # ...write to zf...