如何在Python中创建目录结构的zip存档?


当前回答

显而易见的方法是使用shutil,就像第二个顶级答案所说的那样,但如果出于某种原因,您仍然希望使用ZipFile,并且如果您在执行此操作时遇到一些问题(如Windows等中的ERR 13),您可以使用此修复程序:

import os
import zipfile

def retrieve_file_paths(dirName):
  filePaths = []
  for root, directories, files in os.walk(dirName):
    for filename in files:
        filePath = os.path.join(root, filename)
        filePaths.append(filePath)
  return filePaths
 
def main(dir_name, output_filename):
  filePaths = retrieve_file_paths(dir_name)
   
  zip_file = zipfile.ZipFile(output_filename+'.zip', 'w')
  with zip_file:
    for file in filePaths:
      zip_file.write(file)

main("my_dir", "my_dir_archived")

该方法递归地遍历给定文件夹中的每个子文件夹/文件,并将它们写入zip文件,而不是尝试直接压缩文件夹。

其他回答

现代Python(3.6+)使用pathlib模块对路径进行类似OOP的简洁处理,使用pathlib.Path.rglob()进行递归globing。据我所知,这相当于乔治·V·莱利的回答:压缩压缩,最顶层的元素是目录,保持空目录,使用相对路径。

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不能是Path对象(将在3.6.2+中修复)。

显而易见的方法是使用shutil,就像第二个顶级答案所说的那样,但如果出于某种原因,您仍然希望使用ZipFile,并且如果您在执行此操作时遇到一些问题(如Windows等中的ERR 13),您可以使用此修复程序:

import os
import zipfile

def retrieve_file_paths(dirName):
  filePaths = []
  for root, directories, files in os.walk(dirName):
    for filename in files:
        filePath = os.path.join(root, filename)
        filePaths.append(filePath)
  return filePaths
 
def main(dir_name, output_filename):
  filePaths = retrieve_file_paths(dir_name)
   
  zip_file = zipfile.ZipFile(output_filename+'.zip', 'w')
  with zip_file:
    for file in filePaths:
      zip_file.write(file)

main("my_dir", "my_dir_archived")

该方法递归地遍历给定文件夹中的每个子文件夹/文件,并将它们写入zip文件,而不是尝试直接压缩文件夹。

前面的答案完全忽略了一点,即当您在Windows上运行代码时,使用os.path.join()可以很容易地返回POSIX不兼容的路径。当使用Linux上的任何常用归档软件处理文件时,生成的归档文件将包含名称中带有反斜杠的文件,这不是您想要的。请改用path.as_posix()作为arcname参数!

import zipfile
from pathlib import Path
with zipfile.ZipFile("archive.zip", "w", zipfile.ZIP_DEFLATED) as zf:
    for path in Path("include_all_of_this_folder").rglob("*"):
        zf.write(path, path.as_posix())

如何在Python中创建目录结构的zip存档?

在Python脚本中

在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参数,用于cwd:

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

从shell使用Python

您也可以使用zipfile模块从shell中使用Python执行此操作:

$ python -m zipfile -c zipname sourcedir

其中zipname是所需目标文件的名称(如果需要,请添加.zip,它不会自动执行),sourcedir是目录的路径。

压缩Python(或者只是不需要父目录):

如果您试图用__init__.py和__main__.py压缩一个python包,并且不需要父目录

$ python -m zipfile -c zipname sourcedir/*

And

$ python zipname

将运行程序包。(请注意,不能将子包作为压缩存档的入口点运行。)

压缩Python应用程序:

如果您有python3.5+,并且特别想压缩Python包,请使用ziapp:

$ python -m zipapp myapp
$ python myapp.pyz

要向生成的zip文件添加压缩,请查看此链接。

您需要更改:

zip = zipfile.ZipFile('Python.zip', 'w')

to

zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)