我该如何在Python中创建一个包含目录结构的zip压缩文件?
最简单的方法是使用shutil.make_archive
。它支持zip和tar格式。
import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
如果你需要做一些比整个目录压缩(如跳过某些文件)更复杂的事情,那么你需要像其他人建议的那样深入了解zipfile
模块。shutil
是 Python 标准库的一部分。这应该是最佳答案。 - Alex正如其他人指出的那样,你应该使用 zipfile。文档告诉你哪些函数可用,但并没有真正解释如何使用它们来压缩整个目录。我认为最简单的方法是通过一些示例代码来解释:
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)
os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))
。这样可以让你从任何工作目录压缩一个目录,而不必在归档文件中获取完整的绝对路径。 - Reimundshutil
使得只需一行代码就能非常容易地完成。请查看下面的答案。 - droidlabourziph.write(os.path.join(path,file), arcname=file)
,这样压缩包内的文件名就不是相对于硬盘的路径了。 - Christophe Blinshutil
的下一个答案。 - José L. Patiño要将 mydirectory
目录下的所有文件和子目录添加到一个新的 zip 文件中:
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()
with
代替手动在结尾调用close()
吗? - ArtOfWarfarewith zipfile.ZipFile("myzipfile.zip", "w") as zf: pass
- Subramanya Raoarcname
参数可以解决整个目录分支被压缩而不仅仅是内容的问题。 - Prince如何在Python中创建一个目录结构的zip归档文件?
在Python 2.7+版本中,shutil
模块提供了 make_archive
函数。
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
在这里,压缩文件将被命名为zipfile_name.zip
。如果base_dir
比root_dir
更深,则会排除不在base_dir
中的文件,但仍会归档父目录中到root_dir
的文件。
我在Cygwin上使用2.7进行测试时遇到了问题 - 它希望有一个root_dir
参数,用于当前工作目录:
make_archive('zipfile_name', 'zip', root_dir='.')
你也可以使用Python的zipfile
模块在命令行中完成这个操作:
$ python -m zipfile -c zipname sourcedir
其中zipname
是您想要的目标文件名(如果需要,请添加.zip
,它不会自动执行),sourcedir
是目录的路径。
如果您正在尝试压缩一个带有__init__.py
和__main__.py
的Python包,并且您不想要父级目录,则应该
$ python -m zipfile -c zipname sourcedir/*
而且
$ python zipname
请注意,如果从压缩存档文件运行Python子包作为入口点是不可行的,您只能运行包。
如果您使用的是python3.5+,并且特别想要将Python包压缩起来,请使用zipapp:
$ python -m zipapp myapp
$ python myapp.pyz
这个函数将递归地压缩目录树中的文件,并在归档中记录正确的相对文件名。归档条目与通过 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)
with
语句中使用zipfile
。
感谢指出它是可以的。 - Mitms使用Python 3.9,pathlib
和zipfile
模块,您可以从系统中的任何位置创建 zip 文件。
def zip_dir(dir: Union[Path, str], filename: Union[Path, str]):
"""Zip the provided directory without navigating to that directory using `pathlib` module"""
# Convert to Path object
dir = Path(dir)
with zipfile.ZipFile(filename, "w", zipfile.ZIP_DEFLATED) as zip_file:
for entry in dir.rglob("*"):
zip_file.write(entry, entry.relative_to(dir))
它整洁、有类型,并且代码更少。
使用现代的Python(3.6+),使用pathlib
模块来简洁地面向对象处理路径,以及使用pathlib.Path.rglob()
进行递归式全局匹配。据我所知,这相当于George V. Reilly的答案:带有压缩的zip文件,顶层元素是目录,保留空目录,使用相对路径。
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
from os import PathLike
from typing import Union
def zip_dir(zip_name: str, source_dir: Union[str, PathLike]):
src_path = Path(source_dir).expanduser().resolve(strict=True)
with ZipFile(zip_name, 'w', ZIP_DEFLATED) as zf:
for file in src_path.rglob('*'):
zf.write(file, file.relative_to(src_path.parent))
注意:如可选的类型提示所示,zip_name
不能是一个路径对象(将在3.6.2+中修复)。使用Python标准库中的shutil。
使用shutil非常简单(请参见下面的代码):
代码:
import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
如果要为生成的zip文件添加压缩功能,请查看这个链接。
您需要更改:
zip = zipfile.ZipFile('Python.zip', 'w')
tozip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
#!/usr/bin/env python
import os
import zipfile
def addDirToZip(zipHandle, path, basePath=""):
"""
Adding directory given by \a path to opened zip file \a zipHandle
@param basePath path that will be removed from \a path when adding to archive
Examples:
# add whole "dir" to "test.zip" (when you open "test.zip" you will see only "dir")
zipHandle = zipfile.ZipFile('test.zip', 'w')
addDirToZip(zipHandle, 'dir')
zipHandle.close()
# add contents of "dir" to "test.zip" (when you open "test.zip" you will see only it's contents)
zipHandle = zipfile.ZipFile('test.zip', 'w')
addDirToZip(zipHandle, 'dir', 'dir')
zipHandle.close()
# add contents of "dir/subdir" to "test.zip" (when you open "test.zip" you will see only contents of "subdir")
zipHandle = zipfile.ZipFile('test.zip', 'w')
addDirToZip(zipHandle, 'dir/subdir', 'dir/subdir')
zipHandle.close()
# add whole "dir/subdir" to "test.zip" (when you open "test.zip" you will see only "subdir")
zipHandle = zipfile.ZipFile('test.zip', 'w')
addDirToZip(zipHandle, 'dir/subdir', 'dir')
zipHandle.close()
# add whole "dir/subdir" with full path to "test.zip" (when you open "test.zip" you will see only "dir" and inside it only "subdir")
zipHandle = zipfile.ZipFile('test.zip', 'w')
addDirToZip(zipHandle, 'dir/subdir')
zipHandle.close()
# add whole "dir" and "otherDir" (with full path) to "test.zip" (when you open "test.zip" you will see only "dir" and "otherDir")
zipHandle = zipfile.ZipFile('test.zip', 'w')
addDirToZip(zipHandle, 'dir')
addDirToZip(zipHandle, 'otherDir')
zipHandle.close()
"""
basePath = basePath.rstrip("\\/") + ""
basePath = basePath.rstrip("\\/")
for root, dirs, files in os.walk(path):
# add dir itself (needed for empty dirs
zipHandle.write(os.path.join(root, "."))
# add files
for file in files:
filePath = os.path.join(root, file)
inZipPath = filePath.replace(basePath, "", 1).lstrip("\\/")
#print filePath + " , " + inZipPath
zipHandle.write(filePath, inZipPath)
shutil
中的make_archive
(如果您想要递归压缩单个目录)。不要使用被接受的答案中提出的解决方案。 - malanashutil.make_archive
有关的注意事项 - 它似乎不遵循符号链接。 - LRE