How to create a zip archive of a directory?

539,822

Solution 1

As others have pointed out, you should use zipfile. The documentation tells you what functions are available, but doesn't really explain how you can use them to zip an entire directory. I think it's easiest to explain with some example code:

import os
import zipfile
    
def zipdir(path, ziph):
    # ziph is zipfile handle
    for root, dirs, files in os.walk(path):
        for file in files:
            ziph.write(os.path.join(root, file), 
                       os.path.relpath(os.path.join(root, file), 
                                       os.path.join(path, '..')))

with zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED) as zipf:
    zipdir('tmp/', zipf)

Solution 2

The easiest way is to use shutil.make_archive. It supports both zip and tar formats.

import shutil
shutil.make_archive(output_filename, 'zip', dir_name)

If you need to do something more complicated than zipping the whole directory (such as skipping certain files), then you'll need to dig into the zipfile module as others have suggested.

Solution 3

To add the contents of mydirectory to a new zip file, including all files and subdirectories:

import os
import zipfile

zf = zipfile.ZipFile("myzipfile.zip", "w")
for dirname, subdirs, files in os.walk("mydirectory"):
    zf.write(dirname)
    for filename in files:
        zf.write(os.path.join(dirname, filename))
zf.close()

Solution 4

How can I create a zip archive of a directory structure in Python?

In a Python script

In Python 2.7+, shutil has a make_archive function.

from shutil import make_archive
make_archive(
  'zipfile_name', 
  'zip',           # the archive format - or tar, bztar, gztar 
  root_dir=None,   # root for archive - current working dir if None
  base_dir=None)   # start archiving from here - cwd if None too

Here the zipped archive will be named zipfile_name.zip. If base_dir is farther down from root_dir it will exclude files not in the base_dir, but still archive the files in the parent dirs up to the root_dir.

I did have an issue testing this on Cygwin with 2.7 - it wants a root_dir argument, for cwd:

make_archive('zipfile_name', 'zip', root_dir='.')

Using Python from the shell

You can do this with Python from the shell also using the zipfile module:

$ python -m zipfile -c zipname sourcedir

Where zipname is the name of the destination file you want (add .zip if you want it, it won't do it automatically) and sourcedir is the path to the directory.

Zipping up Python (or just don't want parent dir):

If you're trying to zip up a python package with a __init__.py and __main__.py, and you don't want the parent dir, it's

$ python -m zipfile -c zipname sourcedir/*

And

$ python zipname

would run the package. (Note that you can't run subpackages as the entry point from a zipped archive.)

Zipping a Python app:

If you have python3.5+, and specifically want to zip up a Python package, use zipapp:

$ python -m zipapp myapp
$ python myapp.pyz

Solution 5

This function will recursively zip up a directory tree, compressing the files, and recording the correct relative filenames in the archive. The archive entries are the same as those generated by zip -r output.zip source_dir.

import os
import zipfile
def make_zipfile(output_filename, source_dir):
    relroot = os.path.abspath(os.path.join(source_dir, os.pardir))
    with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as zip:
        for root, dirs, files in os.walk(source_dir):
            # add directory (needed for empty dirs)
            zip.write(root, os.path.relpath(root, relroot))
            for file in files:
                filename = os.path.join(root, file)
                if os.path.isfile(filename): # regular files only
                    arcname = os.path.join(os.path.relpath(root, relroot), file)
                    zip.write(filename, arcname)
Share:
539,822
Admin
Author by

Admin

Updated on December 27, 2021

Comments

  • Admin
    Admin over 2 years

    How can I create a zip archive of a directory structure in Python?

  • George V. Reilly
    George V. Reilly almost 11 years
    The path handling could be greatly simplified by using os.path. See my answer.
  • Reimund
    Reimund almost 11 years
    I would add a second argument to the write call, passing os.path.relpath(os.path.join(root, file), os.path.join(path, '..')). That would let you zip a directory from any working directory, without getting the full absolute paths in the archive.
  • Petter
    Petter over 9 years
    Bug: zipHandle.write(os.path.join(root, ".")) does not take basePath into consideration.
  • Nux
    Nux over 9 years
    Yes, you're probably right. I've later enhnaced this a bit ;-) gist.github.com/Eccenux/17526123107ca0ac28e6
  • Sibbs Gambling
    Sibbs Gambling about 7 years
    There's a funny recursion going on when I try to zip a folder and output the resultant zip to the same folder. :-)
  • Alex
    Alex about 7 years
    shutil is part of the standard python library. This should be the top answer
  • droidlabour
    droidlabour almost 7 years
    shutil makes it really easy in just a single line. Please check the answer below..
  • Christophe Blin
    Christophe Blin almost 7 years
    you may be more interested by doing ziph.write(os.path.join(path,file), arcname=file) so that the filenames inside the archive are not relative to the hard drive
  • aitch-hat
    aitch-hat almost 7 years
    This is the most concise answer here and also has the advantage of adding all subdirectories and files to the archive directly, rather than having everything included in a top-level folder (which results in a redundant level in the folder structure when unzipping).
  • Nishad Up
    Nishad Up over 6 years
    For me this code throwing below error TypeError: invalid file: <zipfile.ZipFile [closed]>
  • std''OrgnlDave
    std''OrgnlDave over 6 years
    @cmcginty could you please be a bit more specific as to what aspect of it is not thread-safe? Will running multiple threads while one calls this cause the interpreter to crash?
  • cmcginty
    cmcginty over 6 years
    @std''OrgnlDave No, it will not crash. The issue I've seen is that files from different threads will be copied into the same zip file. See bugs.python.org/issue30511
  • ArtOfWarfare
    ArtOfWarfare over 6 years
    Can't you use a with instead of having to call close() yourself at the end?
  • dvs
    dvs over 6 years
    Be warned that prior to Python 3.4, shutil.make_archive does not support ZIP64 and will fail on creating ZIP files larger than 2GB.
  • information_interchange
    information_interchange over 6 years
    I am getting "The compressed (zipped) folder is empty" on Windows 7
  • information_interchange
    information_interchange over 6 years
    Ah, I was missing the .close() call!
  • Teekin
    Teekin almost 6 years
    Even though it's not thread-safe, it should still be safe if being used by different threads in different directories, right?
  • Sam Malayek
    Sam Malayek almost 6 years
    @Teekin No. If you look at the bugs report (bugs.python.org/issue30511), you'll see that shutil.make_archive uses os.chdir(). From what I'm reading about os.chdir(), it operates globally.
  • Jane
    Jane over 5 years
    @azdev, what is the solution for shutil.make_archive for files more than 2GB? I had this error(
  • dvs
    dvs over 5 years
    @Jane See the accepted answer or one of the other answers on this page that uses the zipfile library instead of shutil.
  • Tedo Vrbanec
    Tedo Vrbanec over 5 years
    shutil is very, very slow. So, for it is not good option for dirs with large files.
  • Eric
    Eric over 5 years
    @RoachLord: file is not a keyword, even if your editor highlights it as one.
  • Alex
    Alex over 5 years
    This zips, but doesn't compress.
  • sushh
    sushh over 5 years
    please explain with an example so that i can correct my answer
  • Sukanya Pai
    Sukanya Pai over 4 years
    @azdev For python version 3.6 to 3.7 does shutil work safely for files larger than 2GB?
  • SwissNavy
    SwissNavy about 4 years
    If I want to zip a directory instead of the content of directory - is there an option for that? Aslo: can't find what's the equivalent of --remove-files?
  • ingyhere
    ingyhere about 4 years
    Fantastic! Concise! Modern!
  • Georg
    Georg almost 4 years
    However, zipfile "currently cannot create an encrypted file" (from docs.python.org/3.9/library/zipfile.html)
  • mckbrd
    mckbrd almost 4 years
    @SwissNavy see base_dir option
  • Cyborg_Trick
    Cyborg_Trick over 3 years
    I can attest that this is the best answer
  • Usman Liaqat
    Usman Liaqat over 3 years
    Thanks. A quick way to ZIP files.
  • KiDo
    KiDo over 3 years
    I'm trying to automate zipping my work directory which is ~200MB as daily backup, this code kept working and made +84GB and threw an error because my work PC ran out of storage!
  • AndB
    AndB over 3 years
    May also be used with a context manager: with zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED) as zipf: zipdir('tmp/', zipfh)
  • Subramanya Rao
    Subramanya Rao over 3 years
    example: ` with zipfile.ZipFile("myzipfile.zip", "w") as zf: pass `
  • kravb
    kravb about 3 years
    With all the shutil.make_archvie examples here, they all create empty root folders leading up to the folder that you actually want to archive. I do not want my archive file unarchive with "/home/user/Desktop" so everyone can see where folder of interest was originally. How do i just zip "/Directory" and leave out all traces of parent folders?
  • xjcl
    xjcl about 3 years
    Note this is NOT threadsafe! This does an explicit os.chdir which can lead to the wrong directory getting zipped. This led to my zips being gigantic and my disk running out of space.
  • pangyuteng
    pangyuteng about 3 years
    for an actual example using both root_dir and base_dir, see: docs.python.org/3/library/…
  • Shubham_geo
    Shubham_geo about 3 years
    This is not safe,this fails for directories with huge files.
  • Cheng
    Cheng about 3 years
    How come this answer is this far down the page?
  • Pierre
    Pierre about 3 years
    The next answer if more straightforward, and should have been accepted
  • icatalan
    icatalan about 3 years
    What is ziph in this function? path is the directory. What if I have a directory containing other sub-directories? I added a question related to this. stackoverflow.com/questions/67119676/…
  • José L. Patiño
    José L. Patiño almost 3 years
    The next answer does not handle anything related to compression, it just stores the results in a ZIP archive. If you are looking for actual compression, the correct answer is this one and not the next with shutil.
  • José L. Patiño
    José L. Patiño almost 3 years
    This answer is not correct. It doesn't compress anything, plus is slower. the accepted answer is correct and should be the reference.
  • José L. Patiño
    José L. Patiño almost 3 years
    This has been said 3 times already. And it's definitely not the best answer.
  • Tanner Davis
    Tanner Davis almost 3 years
    I want to add that this option lets you make a zip archive with any file extension. i.e. zipfile.ZipFile('Python.meta_zip', 'w') At my work we have to group a metadata dir with files in it and the file they are associated with together. We don't need compression, we just want to easily have them all in one location when we upload them to the cloud.
  • Allen Ellis
    Allen Ellis almost 3 years
    This answer creates a zip containing the directory. How would you change it so that the contents of the directory are added, rather than the directory itself?
  • Drew
    Drew over 2 years
    Does anyone know how to get files referenced by a symlink to copy into the zip archive? When I unzip the created archive a directory for the symlink files is there but the directory is empty.
  • Illegal Operator
    Illegal Operator over 2 years
    Explaining with examples is the only way to explain properly, thanks :)
  • Maile Cupo
    Maile Cupo over 2 years
    This rebuilds the full path to "mydirectory" within the resulting zipfile. i.e. only works as desired if "mydirectory" is in root of your filesystem
  • Mitms
    Mitms over 2 years
    Sweet, I was wondering if zipfile could be used in a with statement. Thanks for pointing out it can.
  • Prince
    Prince about 2 years
    Using the arcname parameter of the write function will solve the issue where the entire directory branch is getting zipped rather than just the contents.
  • Prince
    Prince about 2 years
    Using the arcname parameter of the write function will solve the issue where the entire directory branch is getting zipped rather than just the contents.