Corrupted ZipFile using file object

22 views Asked by At

I'm trying to create, using python, a zip file to be later used in a http response. To achieve this I'm using a io.BytesIO() as file object.

The resulting zip file is somehow corrupted: some software like unzip don't like it while others like zcat do read contents.

Here a minimal example, I will save to file the resulting zip instead of serving in a resoponse. The error is the same I get in my real application:

$ cat << EOF > script.py 
> import io
import zipfile
with (io.BytesIO() as fo, 
zipfile.ZipFile(fo, 'w') as zip,
open('outfile.zip', 'wb') as outfile):
    zip.writestr('file.txt', b'Lorem ipsum')
    fo.seek(0)
    outfile.write(fo.read())
> EOF
$ python3 script.py 
$ ll outfile.zip 
-rw-rw-r-- 1 neurino neurino 49 mar 11 14:38 outfile.zip
$ unzip outfile.zip 
Archive:  outfile.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of outfile.zip or
        outfile.zip.zip, and cannot find outfile.zip.ZIP, period.
$ zcat outfile.zip
Lorem ipsum

Using a file in place of a file object the resulting zip file works — and also is bigger

$ cat << EOF > script2.py 
> import io
> import zipfile
> with zipfile.ZipFile('outfile.zip', 'w') as zip:
>     zip.writestr('file.txt', b'Lorem ipsum')
$ python3 script2.py 
$ ll outfile.zip 
-rw-rw-r-- 1 user user 125 mar 11 14:41 outfile.zip
$ unzip outfile.zip 
Archive:  outfile.zip
 extracting: file.txt     
1

There are 1 answers

0
neurino On

I got the issue myself: I'm reading file object within the with zipfile.ZipFile block, before its __exit__ block gets executed.

This script works as intended:

import io
import zipfile
fo = io.BytesIO()
with zipfile.ZipFile(fo, 'w') as zip:
    zip.writestr('file.txt', b'Lorem ipsum')
fo.seek(0)
with open('outfile.zip', 'wb') as outfile:
    outfile.write(fo.read())