如何创建一个文件夹的压缩包?

865

我该如何在Python中创建一个包含目录结构的zip压缩文件?


78
请使用在被接受答案下面的那个解决方案,使用shutil中的make_archive(如果您想要递归压缩单个目录)。不要使用被接受的答案中提出的解决方案。 - malana
是的,同意@malana - Martha Yi似乎未注册 - 那么是否有通过社区流程更改接受的答案的方法? - Romeo Kienzler
一个与shutil.make_archive有关的注意事项 - 它似乎不遵循符号链接。 - LRE
2
被接受的答案是唯一一个在从目录创建zip文件时实际上是线程安全的,因为每个文件都是单独打开的,锁定对它的读取访问直到文件关闭。 - Beefcake
30个回答

1

1
之前的回答中完全忽视了一个事实,即当您在 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())

1

压缩文件或目录树(包括目录及其子目录)。

from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED

def make_zip(tree_path, zip_path, mode='w', skip_empty_dir=False):
    with ZipFile(zip_path, mode=mode, compression=ZIP_DEFLATED) as zf:
        paths = [Path(tree_path)]
        while paths:
            p = paths.pop()
            if p.is_dir():
                paths.extend(p.iterdir())
                if skip_empty_dir:
                    continue
            zf.write(p)

要追加到现有的归档文件中,请传递 mode='a',要创建新的归档文件,请传递 mode='w'(以上是默认值)。因此,假设您想将3个不同的目录树打包到同一个归档文件中。
make_zip(path_to_tree1, path_to_arch, mode='w')
make_zip(path_to_tree2, path_to_arch, mode='a')
make_zip(path_to_file3, path_to_arch, mode='a')

0
# import required python modules
# You have to install zipfile package using pip install

import os,zipfile

# Change the directory where you want your new zip file to be

os.chdir('Type your destination')

# Create a new zipfile ( I called it myfile )

zf = zipfile.ZipFile('myfile.zip','w')

# os.walk gives a directory tree. Access the files using a for loop

for dirnames,folders,files in os.walk('Type your directory'):
    zf.write('Type your Directory')
    for file in files:
        zf.write(os.path.join('Type your directory',file))

0

在阅读了建议之后,我想出了一种非常相似的方法,可以在不创建“有趣”的目录名称(类似绝对路径的名称)的情况下与2.7.x兼容,并且只会在zip文件中创建指定的文件夹。

或者,如果您需要将所选目录的内容放入zip文件中的文件夹中。

def zipDir( path, ziph ) :
 """
 Inserts directory (path) into zipfile instance (ziph)
 """
 for root, dirs, files in os.walk( path ) :
  for file in files :
   ziph.write( os.path.join( root, file ) , os.path.basename( os.path.normpath( path ) ) + "\\" + file )

def makeZip( pathToFolder ) :
 """
 Creates a zip file with the specified folder
 """
 zipf = zipfile.ZipFile( pathToFolder + 'file.zip', 'w', zipfile.ZIP_DEFLATED )
 zipDir( pathToFolder, zipf )
 zipf.close()
 print( "Zip file saved to: " + pathToFolder)

makeZip( "c:\\path\\to\\folder\\to\\insert\\into\\zipfile" )

0

创建 zip 文件的函数。

def CREATEZIPFILE(zipname, path):
    #function to create a zip file
    #Parameters: zipname - name of the zip file; path - name of folder/file to be put in zip file

    zipf = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
    zipf.setpassword(b"password") #if you want to set password to zipfile

    #checks if the path is file or directory
    if os.path.isdir(path):
        for files in os.listdir(path):
            zipf.write(os.path.join(path, files), files)

    elif os.path.isfile(path):
        zipf.write(os.path.join(path), path)
    zipf.close()

请用示例解释,以便我可以纠正我的答案。 - sushh
然而,zipfile“目前无法创建加密文件”(来自https://docs.python.org/3.9/library/zipfile.html) - Georg

0
这里有一种现代化的方法,使用pathlib和上下文管理器。将文件直接放入zip中,而不是在子文件夹中。
def zip_dir(filename: str, dir_to_zip: pathlib.Path):
    with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
        # Use glob instead of iterdir(), to cover all subdirectories.
        for directory in dir_to_zip.glob('**'):
            for file in directory.iterdir():
                if not file.is_file():
                    continue
                # Strip the first component, so we don't create an uneeded subdirectory
                # containing everything.
                zip_path = pathlib.Path(*file.parts[1:])
                # Use a string, since zipfile doesn't support pathlib  directly.
                zipf.write(str(file), str(zip_path))

0

我通过整合Mark Byers的解决方案和Reimund以及Morten Zilmer的评论(相对路径和包括空目录)来准备一个函数。作为最佳实践,ZipFile的文件构建中使用了with

该函数还准备了一个默认的zip文件名,其中包含压缩目录名称和'.zip'扩展名。因此,它只需要一个参数:要压缩的源目录。

import os
import zipfile

def zip_dir(path_dir, path_file_zip=''):
if not path_file_zip:
    path_file_zip = os.path.join(
        os.path.dirname(path_dir), os.path.basename(path_dir)+'.zip')
with zipfile.ZipFile(path_file_zip, 'wb', zipfile.ZIP_DEFLATED) as zip_file:
    for root, dirs, files in os.walk(path_dir):
        for file_or_dir in files + dirs:
            zip_file.write(
                os.path.join(root, file_or_dir),
                os.path.relpath(os.path.join(root, file_or_dir),
                                os.path.join(path_dir, os.path.pardir)))

0
在使用shutil时,请注意在base_name参数中包含输出目录路径。
import shutil


shutil.make_archive(
  base_name=output_dir_path + output_filename_without_extension, 
  format="zip", 
  root_dir=input_root_dir)

0
总结他人,做一个功能:
import zipfile

def zipFolder(toZipFolder, outputZipFile):
  """
    zip/compress a whole folder/directory to zip file
  """
  print("Zip for foler %s" % toZipFolder)
  with zipfile.ZipFile(outputZipFile, 'w', zipfile.ZIP_DEFLATED) as zipFp:
    for dirpath, dirnames, filenames in os.walk(toZipFolder):
      # print("%s" % ("-"*80))
      # print("dirpath=%s, dirnames=%s, filenames=%s" % (dirpath, dirnames, filenames))
      # print("Folder: %s, Files: %s" % (dirpath, filenames))
      for curFileName in filenames:
        # print("curFileName=%s" % curFileName)
        curFilePath = os.path.join(dirpath, curFileName)
        # print("curFilePath=%s" % curFilePath)
        fileRelativePath = os.path.relpath(curFilePath, toZipFolder)
        # print("fileRelativePath=%s" % fileRelativePath)
        # print("  %s" % fileRelativePath)
        zipFp.write(curFilePath, arcname=fileRelativePath)
  print("Completed zip file %s" % outputZipFile)

打电话:
  toZipFullPath = "/Users/crifan/dev/dev_root/iosReverse/WhatsApp/ipa/forRepackIpa_20231128"
  outputZipFile = "/Users/crifan/dev/dev_root/iosReverse/WhatsApp/ipa/WhatsApp_v23.24.0_20231128.ipa"
  zipFolder(toZipFullPath, outputZipFile)

输出:

Zip for foler /Users/crifan/dev/dev_root/iosReverse/WhatsApp/ipa/forRepackIpa_20231128
Completed zip file /Users/crifan/dev/dev_root/iosReverse/WhatsApp/ipa/WhatsApp_v23.20.79_idaAllSymbols_20231128.ipa

最新代码:crifanLib/crifanFile.py

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接