22

How do I write an in memory zipfile to a file?

# Create in memory zip and add files
zf = zipfile.ZipFile(StringIO.StringIO(), mode='w',compression=zipfile.ZIP_DEFLATED)
zf.writestr('file1.txt', "hi")
zf.writestr('file2.txt', "hi")

# Need to write it out
f = file("C:/path/my_zip.zip", "w")
f.write(zf)  # what to do here? Also tried f.write(zf.read())

f.close()
zf.close()
Joe DF
  • 5,438
  • 6
  • 41
  • 63
user984003
  • 28,050
  • 64
  • 189
  • 285

3 Answers3

38

StringIO.getvalue return content of StringIO:

>>> import StringIO
>>> f = StringIO.StringIO()
>>> f.write('asdf')
>>> f.getvalue()
'asdf'

Alternatively, you can change position of the file using seek:

>>> f.read()
''
>>> f.seek(0)
>>> f.read()
'asdf'

Try following:

mf = StringIO.StringIO()
with zipfile.ZipFile(mf, mode='w', compression=zipfile.ZIP_DEFLATED) as zf:
    zf.writestr('file1.txt', "hi")
    zf.writestr('file2.txt', "hi")

with open("C:/path/my_zip.zip", "wb") as f: # use `wb` mode
    f.write(mf.getvalue())

falsetru
  • 357,413
  • 63
  • 732
  • 636
19

Modify falsetru's answer for python3

1) use io.StringIO instead of StringIO.StringIO

StringIO in python3

2) use b"abc" instead of "abc" , or

python 3.5: TypeError: a bytes-like object is required, not 'str' when writing to a file

3) encode to binary string str.encode(s, "utf-8")

Best way to convert string to bytes in Python 3?

import zipfile
import io
mf = io.BytesIO()

with zipfile.ZipFile(mf, mode="w",compression=zipfile.ZIP_DEFLATED) as zf:

    zf.writestr('file1.txt', b"hi")

    zf.writestr('file2.txt', str.encode("hi"))
    zf.writestr('file3.txt', str.encode("hi",'utf-8'))


with open("a.txt.zip", "wb") as f: # use `wb` mode
    f.write(mf.getvalue())

This should also work for gzip: How do I gzip compress a string in Python?

user3226167
  • 3,131
  • 2
  • 30
  • 34
  • 4
    Python would be such a nice language if they would not have messed up so much with the versions. There should be a way to detect Py3-valid answers... – qwerty_so Jul 25 '19 at 10:00
1
  with ZipFile(read_file, 'r') as zipread:
        with ZipFile(file_write_buffer, 'w', ZIP_DEFLATED) as zipwrite:
            for item in zipread.infolist():
                # Copy all ZipInfo attributes for each file since defaults are not preseved
                dest.CRC = item.CRC
                dest.date_time = item.date_time
                dest.create_system = item.create_system
                dest.compress_type = item.compress_type
                dest.external_attr = item.external_attr
                dest.compress_size = item.compress_size
                dest.file_size = item.file_size
                dest.header_offset = item.header_offset

In the case where the zip file reads corrupted and you notice missing symlinks or corrupted files with wrong timestamps, it could be the fact that the file properties are not getting copied over.

The above code snippet is how I solved the problem.

  • Your code does not seem to do anything with `dest`. Are you missing something like `zipwrite.write(dest)` ? – Andrew Aug 26 '20 at 02:24