【问题标题】:How to create a zip archive of a directory?如何创建目录的 zip 存档?
【发布时间】:2010-12-23 17:29:52
【问题描述】:

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

【问题讨论】:

  • 不要使用已接受答案中建议的解决方案,而是使用shutil 中的make_archive(如果您想递归压缩单个目录)。
  • 是的,同意@malana - Martha Yi 似乎未注册 - 那么现在有办法通过社区流程更改接受的答案吗?
  • 一个警告shutil.make_archive - 它似乎没有遵循符号链接

标签: python zip archive python-zipfile


【解决方案1】:

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

import shutil
shutil.make_archive(output_filename, 'zip', dir_name)

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

【讨论】:

  • shutil 是标准 python 库的一部分。这应该是最佳答案
  • 这是这里最简洁的答案,并且还具有将所有子目录和文件直接添加到存档的优点,而不是将所有内容都包含在顶级文件夹中(这会导致冗余级别)解压时的文件夹结构)。
  • @cmcginty 您能否更具体地说明它的哪些方面不是线程安全的?调用这个时运行多个线程会导致解释器崩溃吗?
  • 请注意,在 Python 3.4 之前,shutil.make_archive 不支持 ZIP64,并且无法创建大于 2GB 的 ZIP 文件。
  • @Teekin 否。如果您查看错误报告 (bugs.python.org/issue30511),您会看到 shutil.make_archive 使用 os.chdir()。从我读到的关于os.chdir() 的内容来看,它在全球范围内运作。
【解决方案2】:

正如其他人指出的那样,您应该使用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, '..')))
      
zipf = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
zipdir('tmp/', zipf)
zipf.close()

【讨论】:

  • 我会在 write 调用中添加第二个参数,传递 os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))。这样您就可以从任何工作目录中压缩目录,而无需在存档中获取完整的绝对路径。
  • 当我尝试压缩一个文件夹并将生成的 zip 输出到同一个文件夹时,会发生一个有趣的递归。 :-)
  • shutil 只需一行代码即可轻松完成。请检查下面的答案..
  • 你可能会更感兴趣 ziph.write(os.path.join(path,file), arcname=file) 这样存档中的文件名与硬盘驱动器无关跨度>
  • 啊,我错过了.close() 电话!
【解决方案3】:

要将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()

【讨论】:

  • 对我来说,这段代码抛出错误 TypeError: invalid file:
  • 你不能使用with 而不是最后自己打电话给close() 吗?
  • 示例:` with zipfile.ZipFile("myzipfile.zip", "w") as zf: pass `
  • 这会在生成的 zip 文件中重建“mydirectory”的完整路径。即仅当“mydirectory”位于文件系统的根目录中时才能按需要工作
【解决方案4】:

如何在 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/*

$ python zipname

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

压缩 Python 应用程序:

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

$ python -m zipapp myapp
$ python myapp.pyz

【讨论】:

    【解决方案5】:

    此函数将递归压缩目录树,压缩文件,并在存档中记录正确的相对文件名。归档条目与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)
    

    【讨论】:

    • 甜蜜,我想知道zipfile 是否可以在with 语句中使用。感谢您指出它可以。
    【解决方案6】:

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

    • 第一个参数:生成的 zip/tar 文件的文件名,
    • 第二个参数:zip/tar,
    • 第三个参数:目录名称

    代码:

    import shutil
    shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
    

    【讨论】:

    • 这里所有的 shutil.make_archvie 示例都创建了空的根文件夹,通向您实际要归档的文件夹。我不希望我的存档文件使用“/home/user/Desktop”取消存档,这样每个人都可以看到感兴趣的文件夹最初的位置。我如何压缩“/Directory”并忽略父文件夹的所有痕迹?
    • 这已经说了3次了。这绝对不是最好的答案。
    【解决方案7】:

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

    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 对象 (would be fixed in 3.6.2+)。

    【讨论】:

    • 太棒了!简洁的!现代!
    【解决方案8】:

    要对生成的 zip 文件添加压缩,请查看 this link

    你需要改变:

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

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

    【讨论】:

      【解决方案9】:

      借助 python 3.9、pathlibzipfile 模块,您可以从系统中的任何位置创建 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))
      

      它整洁、有类型,而且代码更少。

      【讨论】:

        【解决方案10】:

        我对@9​​87654321@ 做了一些更改。如果您有空目录,下面的函数还将添加空目录。示例应该更清楚地说明添加到 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)
        

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

        【讨论】:

        【解决方案11】:

        我有另一个可能有帮助的代码示例,使用 python3、pathlib 和 zipfile。 它应该适用于任何操作系统。

        from pathlib import Path
        import zipfile
        from datetime import datetime
        
        DATE_FORMAT = '%y%m%d'
        
        
        def date_str():
            """returns the today string year, month, day"""
            return '{}'.format(datetime.now().strftime(DATE_FORMAT))
        
        
        def zip_name(path):
            """returns the zip filename as string"""
            cur_dir = Path(path).resolve()
            parent_dir = cur_dir.parents[0]
            zip_filename = '{}/{}_{}.zip'.format(parent_dir, cur_dir.name, date_str())
            p_zip = Path(zip_filename)
            n = 1
            while p_zip.exists():
                zip_filename = ('{}/{}_{}_{}.zip'.format(parent_dir, cur_dir.name,
                                                     date_str(), n))
                p_zip = Path(zip_filename)
                n += 1
            return zip_filename
        
        
        def all_files(path):
            """iterator returns all files and folders from path as absolute path string
            """
            for child in Path(path).iterdir():
                yield str(child)
                if child.is_dir():
                    for grand_child in all_files(str(child)):
                        yield str(Path(grand_child))
        
        
        def zip_dir(path):
            """generate a zip"""
            zip_filename = zip_name(path)
            zip_file = zipfile.ZipFile(zip_filename, 'w')
            print('create:', zip_filename)
            for file in all_files(path):
                print('adding... ', file)
                zip_file.write(file)
            zip_file.close()
        
        
        if __name__ == '__main__':
            zip_dir('.')
            print('end!')
        

        【讨论】:

          【解决方案12】:

          对于保留要归档的父目录下的文件夹层次结构的简洁方法:

          import glob
          import zipfile
          
          with zipfile.ZipFile(fp_zip, "w", zipfile.ZIP_DEFLATED) as zipf:
              for fp in glob(os.path.join(parent, "**/*")):
                  base = os.path.commonpath([parent, fp])
                  zipf.write(fp, arcname=fp.replace(base, ""))
          

          如果需要,您可以将其更改为使用 pathlib for file globbing

          【讨论】:

            【解决方案13】:

            如果您想要任何通用图形文件管理器的压缩文件夹等功能,您可以使用以下代码,它使用zipfile 模块。使用此代码,您将拥有以路径作为根文件夹的 zip 文件。

            import os
            import zipfile
            
            def zipdir(path, ziph):
                # Iterate all the directories and files
                for root, dirs, files in os.walk(path):
                    # Create a prefix variable with the folder structure inside the path folder. 
                    # So if a file is at the path directory will be at the root directory of the zip file
                    # so the prefix will be empty. If the file belongs to a containing folder of path folder 
                    # then the prefix will be that folder.
                    if root.replace(path,'') == '':
                            prefix = ''
                    else:
                            # Keep the folder structure after the path folder, append a '/' at the end 
                            # and remome the first character, if it is a '/' in order to have a path like 
                            # folder1/folder2/file.txt
                            prefix = root.replace(path, '') + '/'
                            if (prefix[0] == '/'):
                                    prefix = prefix[1:]
                    for filename in files:
                            actual_file_path = root + '/' + filename
                            zipped_file_path = prefix + filename
                            zipf.write( actual_file_path, zipped_file_path)
            
            
            zipf = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
            zipdir('/tmp/justtest/', zipf)
            zipf.close()
            

            【讨论】:

              【解决方案14】:

              您可能想查看zipfile 模块; http://docs.python.org/library/zipfile.html 有文档。

              您可能还希望os.walk() 为目录结构编制索引。

              【讨论】:

                【解决方案15】:

                以下是 Nux 给出的对我有用的答案的变体:

                def WriteDirectoryToZipFile( zipHandle, srcPath, zipLocalPath = "", zipOperation = zipfile.ZIP_DEFLATED ):
                    basePath = os.path.split( srcPath )[ 0 ]
                    for root, dirs, files in os.walk( srcPath ):
                        p = os.path.join( zipLocalPath, root [ ( len( basePath ) + 1 ) : ] )
                        # add dir
                        zipHandle.write( root, p, zipOperation )
                        # add files
                        for f in files:
                            filePath = os.path.join( root, f )
                            fileInZipPath = os.path.join( p, f )
                            zipHandle.write( filePath, fileInZipPath, zipOperation )
                

                【讨论】:

                  【解决方案16】:

                  试试下面的。它对我有用

                  import zipfile, os
                  zipf = "compress.zip"  
                  def main():
                      directory = r"Filepath"
                      toZip(directory)
                  def toZip(directory):
                      zippedHelp = zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED )
                  
                      list = os.listdir(directory)
                      for file_list in list:
                          file_name = os.path.join(directory,file_list)
                  
                          if os.path.isfile(file_name):
                              print file_name
                              zippedHelp.write(file_name)
                          else:
                              addFolderToZip(zippedHelp,file_list,directory)
                              print "---------------Directory Found-----------------------"
                      zippedHelp.close()
                  
                  def addFolderToZip(zippedHelp,folder,directory):
                      path=os.path.join(directory,folder)
                      print path
                      file_list=os.listdir(path)
                      for file_name in file_list:
                          file_path=os.path.join(path,file_name)
                          if os.path.isfile(file_path):
                              zippedHelp.write(file_path)
                          elif os.path.isdir(file_name):
                              print "------------------sub directory found--------------------"
                              addFolderToZip(zippedHelp,file_name,path)
                  
                  
                  if __name__=="__main__":
                      main()
                  

                  【讨论】:

                    【解决方案17】:

                    为了提供更大的灵活性,例如按名称选择目录/文件使用:

                    import os
                    import zipfile
                    
                    def zipall(ob, path, rel=""):
                        basename = os.path.basename(path)
                        if os.path.isdir(path):
                            if rel == "":
                                rel = basename
                            ob.write(path, os.path.join(rel))
                            for root, dirs, files in os.walk(path):
                                for d in dirs:
                                    zipall(ob, os.path.join(root, d), os.path.join(rel, d))
                                for f in files:
                                    ob.write(os.path.join(root, f), os.path.join(rel, f))
                                break
                        elif os.path.isfile(path):
                            ob.write(path, os.path.join(rel, basename))
                        else:
                            pass
                    

                    对于文件树:

                    .
                    ├── dir
                    │   ├── dir2
                    │   │   └── file2.txt
                    │   ├── dir3
                    │   │   └── file3.txt
                    │   └── file.txt
                    ├── dir4
                    │   ├── dir5
                    │   └── file4.txt
                    ├── listdir.zip
                    ├── main.py
                    ├── root.txt
                    └── selective.zip
                    

                    你可以例如只选择dir4root.txt

                    cwd = os.getcwd()
                    files = [os.path.join(cwd, f) for f in ['dir4', 'root.txt']]
                    
                    with zipfile.ZipFile("selective.zip", "w" ) as myzip:
                        for f in files:
                            zipall(myzip, f)
                    

                    或者只是在脚本调用目录中 listdir 并从那里添加所有内容:

                    with zipfile.ZipFile("listdir.zip", "w" ) as myzip:
                        for f in os.listdir():
                            if f == "listdir.zip":
                                # Creating a listdir.zip in the same directory
                                # will include listdir.zip inside itself, beware of this
                                continue
                            zipall(myzip, f)
                    

                    【讨论】:

                    • 这个压缩,但不压缩。
                    【解决方案18】:

                    假设您要压缩当前目录中的所有文件夹(子目录)。

                    for root, dirs, files in os.walk("."):
                        for sub_dir in dirs:
                            zip_you_want = sub_dir+".zip"
                            zip_process = zipfile.ZipFile(zip_you_want, "w", zipfile.ZIP_DEFLATED)
                            zip_process.write(file_you_want_to_include)
                            zip_process.close()
                    
                            print("Successfully zipped directory: {sub_dir}".format(sub_dir=sub_dir))
                    

                    【讨论】:

                      【解决方案19】:

                      这里有这么多答案,我希望我可以用我自己的版本做出贡献,该版本基于原始答案(顺便说一下),但具有更图形化的视角,还为每个 zipfile 设置和排序使用上下文os.walk(),为了有一个有序的输出。

                      拥有这些文件夹和文件(以及其他文件夹),我想为每个 cap_ 文件夹创建一个 .zip

                      $ tree -d
                      .
                      ├── cap_01
                      |    ├── 0101000001.json
                      |    ├── 0101000002.json
                      |    ├── 0101000003.json
                      |
                      ├── cap_02
                      |    ├── 0201000001.json
                      |    ├── 0201000002.json
                      |    ├── 0201001003.json
                      |
                      ├── cap_03
                      |    ├── 0301000001.json
                      |    ├── 0301000002.json
                      |    ├── 0301000003.json
                      | 
                      ├── docs
                      |    ├── map.txt
                      |    ├── main_data.xml
                      |
                      ├── core_files
                           ├── core_master
                           ├── core_slave
                      

                      这是我申请的,用 cmets 更好地理解这个过程。

                      $ cat zip_cap_dirs.py 
                      """ Zip 'cap_*' directories. """           
                      import os                                                                       
                      import zipfile as zf                                                            
                      
                      
                      for root, dirs, files in sorted(os.walk('.')):                                                                                               
                          if 'cap_' in root:                                                          
                              print(f"Compressing: {root}")                                           
                              # Defining .zip name, according to Capítulo.                            
                              cap_dir_zip = '{}.zip'.format(root)                                     
                              # Opening zipfile context for current root dir.                         
                              with zf.ZipFile(cap_dir_zip, 'w', zf.ZIP_DEFLATED) as new_zip:          
                                  # Iterating over os.walk list of files for the current root dir.    
                                  for f in files:                                                     
                                      # Defining relative path to files from current root dir.        
                                      f_path = os.path.join(root, f)                                  
                                      # Writing the file on the .zip file of the context              
                                      new_zip.write(f_path) 
                      

                      基本上,对于os.walk(path) 的每次迭代,我都会为zipfile 设置打开一个上下文,然后在files 上进行迭代,这是list 来自root 目录的文件的list,形成每个文件的相对路径基于当前root 目录,附加到正在运行的zipfile 上下文。

                      输出如下所示:

                      $ python3 zip_cap_dirs.py
                      Compressing: ./cap_01
                      Compressing: ./cap_02
                      Compressing: ./cap_03
                      

                      要查看每个.zip目录的内容,可以使用less命令:

                      $ less cap_01.zip
                      
                      Archive:  cap_01.zip
                       Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
                      --------  ------  ------- ---- ---------- ----- --------  ----
                        22017  Defl:N     2471  89% 2019-09-05 08:05 7a3b5ec6  cap_01/0101000001.json
                        21998  Defl:N     2471  89% 2019-09-05 08:05 155bece7  cap_01/0101000002.json
                        23236  Defl:N     2573  89% 2019-09-05 08:05 55fced20  cap_01/0101000003.json
                      --------          ------- ---                           -------
                        67251             7515  89%                            3 files
                      

                      【讨论】:

                        【解决方案20】:

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

                        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')
                        

                        【讨论】:

                          【解决方案21】:

                          使用pathlib.Path 的解决方案,独立于所使用的操作系统:

                          import zipfile
                          from pathlib import Path
                          
                          def zip_dir(path: Path, zip_file_path: Path):
                              """Zip all contents of path to zip_file"""
                              files_to_zip = [
                                  file for file in path.glob('*') if file.is_file()]
                              with zipfile.ZipFile(
                                  zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zip_f:
                                  for file in files_to_zip:
                                      print(file.name)
                                      zip_f.write(file, file.name)
                          
                          current_dir = Path.cwd()  
                          zip_dir = current_dir / "test"
                          tools.zip_dir(
                              zip_dir, current_dir / 'Zipped_dir.zip')
                          

                          【讨论】:

                            【解决方案22】:

                            显而易见的方法是使用shutil,就像第二个最佳答案所说的那样,但是如果您出于某种原因仍然希望使用ZipFile,并且在这样做时遇到了麻烦(例如ERR 13 in Windows 等),您可以使用此修复:

                            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 文件,而不是尝试直接压缩文件夹。

                            【讨论】:

                              【解决方案23】:

                              这是一种现代方法,使用 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))
                              

                              【讨论】:

                                【解决方案24】:

                                我通过将 Mark Byers 的解决方案与 Reimund 和 Morten Zilmer 的 cmets(相对路径并包括空目录)合并来准备一个函数。作为最佳实践,with 用于 ZipFile 的文件构造。

                                该函数还准备了一个带有压缩目录名称和“.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)))
                                

                                【讨论】:

                                  【解决方案25】:
                                  # 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))
                                  

                                  【讨论】:

                                    【解决方案26】:

                                    好吧,在阅读了建议之后,我想出了一种非常相似的方法,它可以在 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" )
                                    

                                    【讨论】:

                                      【解决方案27】:

                                      创建 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()
                                      

                                      【讨论】:

                                      【解决方案28】:

                                      对于其他任何钻研这个问题并试图归档他们的程序所在的目录并且得到非常深的树结构并由于 zip 文件压缩本身而导致递归的人,试试这个。

                                      它结合了Mark's answer 和一些额外的检查,以确保没有对 zip 文件本身进行递归压缩,也没有不必要的深度文件夹结构。

                                      import os
                                      import zipfile
                                      
                                      def zipdir(path, ziph, ignored_directories, ignored_files):
                                          # ziph is zipfile handle
                                          for root, dirs, files in os.walk(path):
                                            for file in files:
                                              if not any(ignored_dir in root for ignored_dir in ignored_directories):
                                                if not any(ignored_fname in file for ignored_fname in ignored_files):
                                                  ziph.write(os.path.join(root, file))
                                      
                                      # current working directory
                                      this_dir = os.path.dirname(os.path.abspath(__file__))
                                      
                                      # the directory within the working directory the zip will be created in (build/archives).
                                      zip_dest_dir = os.path.join('build', 'archives')
                                      
                                      # verify zip_dest_dir exists: if not, create it
                                      if not os.path.isdir(zip_dest_dir):
                                          os.makedirs(zip_dest_dir, exist_ok=True)
                                      
                                      # leave zip_dest_dir blank (or set dist_dir = this_dir) if you want the zip file in the working directory (same directory as the script)
                                      dest_dir = os.path.join(this_dir, zip_dest_dir)
                                      
                                      # name the zip file: remember the file extension
                                      zip_filename = 'zipped_directory.zip'
                                      
                                      # zip file's path
                                      zip_path = os.path.join(dest_dir, zip_filename)
                                      
                                      # create the zipfile handle: you can change ZIP_STORED to any other compression algorithm of your choice, like ZIP_DEFLATED, if you need actual compression
                                      zipf = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_STORED)
                                      
                                      # ignored files and directories: I personally wanted to ignore the "build" directory, alongside with "node_modules", so those would be listed here.
                                      ignored_dirs = []
                                      
                                      # ignore any specific files: in my case, I was ignoring the script itself, so I'd include 'deploy.py' here
                                      ignored_files = [zip_filename]
                                      
                                      # zip directory contents
                                      zipdir('.', zipf, ignored_dirs, ignored_files)
                                      zipf.close()
                                      

                                      生成的 zip 文件应该只包含从工作目录开始的目录:因此没有 Users/user/Desktop/code/.../working_directory/.../etc。一种文件结构。

                                      【讨论】:

                                        猜你喜欢
                                        • 2011-01-31
                                        • 2016-08-20
                                        • 2012-07-25
                                        • 1970-01-01
                                        • 2010-11-12
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多