How to create a zip archive of a directory?
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)
Admin
Updated on December 27, 2021Comments
-
Admin over 2 years
How can I create a zip archive of a directory structure in Python?
-
George V. Reilly almost 11 yearsThe path handling could be greatly simplified by using os.path. See my answer.
-
Reimund almost 11 yearsI 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 over 9 yearsBug: zipHandle.write(os.path.join(root, ".")) does not take basePath into consideration.
-
Nux over 9 yearsYes, you're probably right. I've later enhnaced this a bit ;-) gist.github.com/Eccenux/17526123107ca0ac28e6
-
Sibbs Gambling about 7 yearsThere's a funny recursion going on when I try to zip a folder and output the resultant zip to the same folder. :-)
-
Alex about 7 years
shutil
is part of the standard python library. This should be the top answer -
droidlabour almost 7 years
shutil
makes it really easy in just a single line. Please check the answer below.. -
Christophe Blin almost 7 yearsyou 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 almost 7 yearsThis 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 over 6 yearsFor me this code throwing below error TypeError: invalid file: <zipfile.ZipFile [closed]>
-
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 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 over 6 yearsCan't you use a
with
instead of having to callclose()
yourself at the end? -
dvs over 6 yearsBe 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 over 6 yearsI am getting "The compressed (zipped) folder is empty" on Windows 7
-
information_interchange over 6 yearsAh, I was missing the
.close()
call! -
Teekin almost 6 yearsEven though it's not thread-safe, it should still be safe if being used by different threads in different directories, right?
-
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
usesos.chdir()
. From what I'm reading aboutos.chdir()
, it operates globally. -
Jane over 5 years@azdev, what is the solution for shutil.make_archive for files more than 2GB? I had this error(
-
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 over 5 yearsshutil is very, very slow. So, for it is not good option for dirs with large files.
-
Eric over 5 years@RoachLord:
file
is not a keyword, even if your editor highlights it as one. -
Alex over 5 yearsThis zips, but doesn't compress.
-
sushh over 5 yearsplease explain with an example so that i can correct my answer
-
Sukanya Pai over 4 years@azdev For python version 3.6 to 3.7 does shutil work safely for files larger than 2GB?
-
SwissNavy about 4 yearsIf 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 about 4 yearsFantastic! Concise! Modern!
-
Georg almost 4 yearsHowever, zipfile "currently cannot create an encrypted file" (from docs.python.org/3.9/library/zipfile.html)
-
mckbrd almost 4 years@SwissNavy see
base_dir
option -
Cyborg_Trick over 3 yearsI can attest that this is the best answer
-
Usman Liaqat over 3 yearsThanks. A quick way to ZIP files.
-
KiDo over 3 yearsI'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 over 3 yearsMay also be used with a context manager:
with zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED) as zipf: zipdir('tmp/', zipfh)
-
Subramanya Rao over 3 yearsexample: ` with zipfile.ZipFile("myzipfile.zip", "w") as zf: pass `
-
kravb about 3 yearsWith 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 about 3 yearsNote 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 about 3 yearsfor an actual example using both root_dir and base_dir, see: docs.python.org/3/library/…
-
Shubham_geo about 3 yearsThis is not safe,this fails for directories with huge files.
-
Cheng about 3 yearsHow come this answer is this far down the page?
-
Pierre about 3 yearsThe next answer if more straightforward, and should have been accepted
-
icatalan about 3 yearsWhat 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 almost 3 yearsThe 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 almost 3 yearsThis 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 almost 3 yearsThis has been said 3 times already. And it's definitely not the best answer.
-
Tanner Davis almost 3 yearsI 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 almost 3 yearsThis 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 over 2 yearsDoes 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 over 2 yearsExplaining with examples is the only way to explain properly, thanks :)
-
Maile Cupo over 2 yearsThis 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 over 2 yearsSweet, I was wondering if
zipfile
could be used in awith
statement. Thanks for pointing out it can. -
Prince about 2 yearsUsing 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 about 2 yearsUsing the
arcname
parameter of the write function will solve the issue where the entire directory branch is getting zipped rather than just the contents.