如何创建目录的zip存档

Mar*_* Yi 417 python zip archive zipfile directory-tree

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

crd*_*vis 827

最简单的方法是使用shutil.make_archive.它支持zip和tar格式.

import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
Run Code Online (Sandbox Code Playgroud)

如果你需要做一些比压缩整个目录更复杂的事情(比如跳过某些文件),那么你需要像其他人建议的那样深入研究zipfile模块.

  • `shutil`是标准python库的一部分.这应该是最好的答案 (77认同)
  • **警告:shutil.make_archive不是线程安全的** (19认同)
  • 请注意,在Python 3.4之前,shutil.make_archive不支持ZIP64,并且在创建大于2GB的ZIP文件时将失败. (8认同)
  • @cmcginty你可以更具体一点,它的哪个方面不是线程安全的?在调用此函数时运行多个线程会导致解释器崩溃吗? (3认同)
  • 这个答案不正确。它不压缩任何东西,而且速度较慢。接受的答案是正确的,应该作为参考。 (3认同)
  • 这是这里最简洁的答案,并且还具有直接将所有子目录和文件添加到存档中的优点,而不是将所有内容都包含在顶级文件夹中(解压缩后在文件夹结构中导致冗余级别)。 (2认同)
  • @Teekin否。如果查看bug报告(bugs.python.org/issue30511),您会看到`shutil.make_archive`使用`os.chdir()`。根据我对`os.chdir()`的了解,它在全球范围内运作。 (2认同)
  • Shutil 非常非常慢。因此,对于具有大文件的目录来说,这不是一个好的选择。 (2认同)

Mar*_*ers 472

正如其他人指出的那样,你应该使用zipfile.文档告诉您哪些功能可用,但没有真正解释如何使用它们来压缩整个目录.我认为最简单的解释一些示例代码:

#!/usr/bin/env python
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))

if __name__ == '__main__':
    zipf = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
    zipdir('tmp/', zipf)
    zipf.close()
Run Code Online (Sandbox Code Playgroud)

改编自:http://www.devshed.com/c/a/Python/Python-UnZipped/

  • 我会在write调用中添加第二个参数,传递`os.path.relpath(os.path.join(root,file),os.path.join(path,'..'))`.这样您就可以从任何工作目录中压缩目录,而无需获取存档中的完整绝对路径. (113认同)
  • 当我尝试压缩文件夹并将结果zip输出到同一文件夹时,会发生一个有趣的递归.:-) (7认同)
  • `shutil`只需一行即可轻松实现.请检查下面的答案.. (7认同)
  • 你可能对ziph.write(os.path.join(path,file),arcname = file)感兴趣,这样档案里面的文件名就不会相对于硬盘了 (7认同)
  • 下一个答案不处理与压缩相关的任何内容,它只是将结果存储在 ZIP 存档中。如果您正在寻找实际的压缩,正确的答案是这个,而不是下一个“shutil”。 (2认同)

Ben*_*mes 62

要将内容添加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()
Run Code Online (Sandbox Code Playgroud)

  • 难道你不能使用`with`而不是自己最后调用`close()`吗? (7认同)
  • 这将在生成的 zip 文件中重建“mydirectory”的完整路径。ie 仅当“mydirectory”位于文件系统的根目录中时才按需要工作 (3认同)

Aar*_*all 47

如何在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
Run Code Online (Sandbox Code Playgroud)

这里将命名压缩存档zipfile_name.zip.如果base_dir距离较远root_dir,它将排除不在base_dir的文件,但仍然将父目录中的文件存档到root_dir.

我确实在Cygwin上用2.7测试了这个问题 - 它想要一个root_dir参数,对于cwd:

make_archive('zipfile_name', 'zip', root_dir='.')
Run Code Online (Sandbox Code Playgroud)

从shell使用Python

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

$ python -m zipfile -c zipname sourcedir
Run Code Online (Sandbox Code Playgroud)

zipname您想要的目标文件的名称在哪里(.zip如果需要,可以添加,不会自动添加),sourcedir是目录的路径.

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

如果你想拉上一个Python包用__init__.py__main__.py,和你不想要的父目录,它是

$ python -m zipfile -c zipname sourcedir/*
Run Code Online (Sandbox Code Playgroud)

$ python zipname
Run Code Online (Sandbox Code Playgroud)

会运行包.(请注意,您无法将子包作为压缩存档的入口点运行.)

压缩Python应用程序:

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

$ python -m zipapp myapp
$ python myapp.pyz
Run Code Online (Sandbox Code Playgroud)


Geo*_*lly 31

此函数将递归压缩目录树,压缩文件,并在归档中记录正确的相对文件名.存档条目与生成的条目相同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)
Run Code Online (Sandbox Code Playgroud)


JD *_*nki 31

使用 python 3.9pathlibzipfile模块,您可以从系统中的任何位置创建 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))
Run Code Online (Sandbox Code Playgroud)

它很整洁,有打字功能,并且代码较少。


mon*_*ime 16

现代 Python (3.6+) 使用该pathlib模块进行类似 OOP 的简洁路径处理以及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))
Run Code Online (Sandbox Code Playgroud)

注意:正如可选类型提示所示,zip_name不能是 Path 对象(将在 3.6.2+ 中修复)。

  • 极好的!简洁的!现代的! (4认同)

Vad*_*S J 16

使用shutil,它是python标准库集的一部分.使用shutil非常简单(参见下面的代码):

  • 1st arg:结果zip/tar文件的文件名,
  • 第2个arg:zip/tar,
  • 第3个arg:dir_name

码:

import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
Run Code Online (Sandbox Code Playgroud)


小智 11

要将压缩添加到生成的zip文件,请查看此链接.

你需要改变:

zip = zipfile.ZipFile('Python.zip', 'w')
Run Code Online (Sandbox Code Playgroud)

zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
Run Code Online (Sandbox Code Playgroud)


rya*_*lon 6

要保留要归档的父目录下的文件夹层次结构:

from pathlib import Path
import zipfile

fp_zip = Path("output.zip")
path_to_archive = Path("./path-to-archive")

with zipfile.ZipFile(fp_zip, "w", zipfile.ZIP_DEFLATED) as zipf:
    for fp in path_to_archive.glob("**/*"):
        zipf.write(fp, arcname=fp.relative_to(path_to_archive))
Run Code Online (Sandbox Code Playgroud)


Nux*_*Nux 5

我对Mark Byers给出的代码做了一些修改.如果你有它们,下面的函数也会添加空目录.示例应该更清楚地说明添加到zip的路径是什么.

#!/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)
Run Code Online (Sandbox Code Playgroud)

以上是一个简单的功能,适用于简单的情况.您可以在我的Gist中找到更优雅的课程:https: //gist.github.com/Eccenux/17526123107ca0ac28e6