【问题标题】:Adding folders to a zip file using python使用python将文件夹添加到zip文件
【发布时间】:2010-10-02 06:53:51
【问题描述】:

我想创建一个 zip 文件。将文件夹添加到 zip 文件中,然后将一堆文件添加到该文件夹​​中。

所以我想最终得到一个包含单个文件夹的 zip 文件。

我不知道在 zip 文件中包含文件夹或其他东西是否是不好的做法,但谷歌没有给我任何关于这个主题的信息。

我是从这个开始的:

def addFolderToZip(myZipFile,folder):
    folder = folder.encode('ascii') #convert path to ascii for ZipFile Method
    for file in glob.glob(folder+"/*"):
            if os.path.isfile(file):
                print file
                myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED)
            elif os.path.isdir(file):
                addFolderToZip(myZipFile,file)

def createZipFile(filename,files,folders):
    curTime=strftime("__%Y_%m_%d", time.localtime())
    filename=filename+curTime;
    print filename
    zipFilename=utils.getFileName("files", filename+".zip")
    myZipFile = zipfile.ZipFile( zipFilename, "w" ) # Open the zip file for writing 
    for file in files:
        file = file.encode('ascii') #convert path to ascii for ZipFile Method
        if os.path.isfile(file):
            (filepath, filename) = os.path.split(file)
            myZipFile.write( file, filename, zipfile.ZIP_DEFLATED )

    for folder in  folders:   
        addFolderToZip(myZipFile,folder)  
    myZipFile.close()
    return (1,zipFilename)


(success,filename)=createZipFile(planName,files,folders);

取自:http://mail.python.org/pipermail/python-list/2006-August/396166.html

删除所有文件夹并将目标文件夹(及其子文件夹)中的所有文件放入单个 zip 文件中。我无法让它添加整个文件夹。

如果我将路径输入到 myZipFile.write 中的文件夹,我会得到

IOError: [Errno 13] Permission denied: '..\packed\bin'

非常欢迎任何帮助。

相关问题:How do I zip the contents of a folder using python (version 2.5)?

【问题讨论】:

    标签: python file zip directory zipfile


    【解决方案1】:

    对我来说最简单的方法是使用zipfile CLI(命令行界面)。 zipfile CLI 可以将文件或文件夹作为参数,并将它们递归地添加到存档中。

    因此,如果您有以下文件层次结构:

    - file1.txt
    - folder1 
       - file2.txt
       - file3.txt
    

    如果您希望将所有内容归档到“result.zip”中,您只需编写:

    python -m zipfile -c result.zip file1.txt folder
    

    如果你想在python代码中使用它并使用导入的zipfile模块,你可以通过以下方式调用它的main函数:

    import zipfile
    zipfile.main(['-c', 'result.zip', 'file1.md', 'folder'])
    

    【讨论】:

    【解决方案2】:

    你也可以使用shutil

    import shutil
    
    zip_name = 'path\to\zip_file'
    directory_name = 'path\to\directory'
    
    # Create 'path\to\zip_file.zip'
    shutil.make_archive(zip_name, 'zip', directory_name)
    

    这会将整个文件夹放入 zip 中。

    【讨论】:

    • 仅适用于 Python 2.7+
    • 该方法的一个有趣之处在于,它会将.zip 附加到您的desired_zipfile_name_no,即使它已经具有.zip 扩展名。然后它返回它使用新扩展写入的完整路径。 (您可以使用除 zip 之外的其他格式,我希望它也会附加它们的扩展名。)
    • 它不保留符号链接
    • 这看起来不错,但是我无法修改压缩文件的目标路径,我尝试将 dir 添加为第 4 个参数但它不起作用。
    • 谢谢!这看起来更像。我很困惑 ZipFile.write(path, arcname) 只是忽略了path 的内容,如果它是一个文件夹,只是在 zip 中创建空文件夹。这有什么用?!?!为什么这是标准行为!?!? :|
    【解决方案3】:
    import os
    import zipfile
    
    zf = zipfile.ZipFile("file.zip", "w")
    for file in os.listdir(os.curdir):
        if not file.endswith('.zip') and os.path.isfile(os.curdir+'/'+file):
            print file
            zf.write(file)
        elif os.path.isdir(os.curdir+'/'+file):
            print f
            for f in os.listdir(os.curdir+'/'+file):
                zf.write(file+'\\'+f)
    zf.close()
    

    【讨论】:

    • 这不适用于嵌套子目录:如果您的 dir 包含 subdir 包含 file.txt,那么您就不走运了。更好地创建递归函数。
    【解决方案4】:
    import zipfile
    import os
    
    
    class ZipUtilities:
    
        def toZip(self, file, filename):
            zip_file = zipfile.ZipFile(filename, 'w')
            if os.path.isfile(file):
                        zip_file.write(file)
                else:
                        self.addFolderToZip(zip_file, file)
            zip_file.close()
    
        def addFolderToZip(self, zip_file, folder): 
            for file in os.listdir(folder):
                full_path = os.path.join(folder, file)
                if os.path.isfile(full_path):
                    print 'File added: ' + str(full_path)
                    zip_file.write(full_path)
                elif os.path.isdir(full_path):
                    print 'Entering folder: ' + str(full_path)
                    self.addFolderToZip(zip_file, full_path)
    
    def main():
        utilities = ZipUtilities()
        filename = 'TEMP.zip'
        directory = 'TEMP'
        utilities.toZip(directory, filename)
    
    main()
    

    我在跑步:

    python tozip.py
    

    这是日志:

    havok@fireshield:~$ python tozip.py
    
    File added: TEMP/NARF (7ª copia)
    Entering folder: TEMP/TEMP2
    File added: TEMP/TEMP2/NERF (otra copia)
    File added: TEMP/TEMP2/NERF (copia)
    File added: TEMP/TEMP2/NARF
    File added: TEMP/TEMP2/NARF (copia)
    File added: TEMP/TEMP2/NARF (otra copia)
    Entering folder: TEMP/TEMP2/TEMP3
    File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL
    File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL (copia)
    File added: TEMP/TEMP2/NERF
    File added: TEMP/NARF (copia) (otra copia)
    File added: TEMP/NARF (copia) (copia)
    File added: TEMP/NARF (6ª copia)
    File added: TEMP/NERF (copia) (otra copia)
    File added: TEMP/NERF (4ª copia)
    File added: TEMP/NERF (otra copia)
    File added: TEMP/NERF (3ª copia)
    File added: TEMP/NERF (6ª copia)
    File added: TEMP/NERF (copia)
    File added: TEMP/NERF (5ª copia)
    File added: TEMP/NARF (8ª copia)
    File added: TEMP/NARF (3ª copia)
    File added: TEMP/NARF (5ª copia)
    File added: TEMP/NERF (copia) (3ª copia)
    File added: TEMP/NARF
    File added: TEMP/NERF (copia) (copia)
    File added: TEMP/NERF (8ª copia)
    File added: TEMP/NERF (7ª copia)
    File added: TEMP/NARF (copia)
    File added: TEMP/NARF (otra copia)
    File added: TEMP/NARF (4ª copia)
    File added: TEMP/NERF
    File added: TEMP/NARF (copia) (3ª copia)
    

    如您所见,它可以工作,存档也可以。这是一个递归函数,可以压缩整个文件夹。唯一的问题是它不会创建一个空文件夹。

    干杯。

    【讨论】:

    • 清洁度挑剔:将@staticmethod装饰器添加到defs,使用ZipUtilities.而不是self.
    【解决方案5】:

    如果您查看使用 Info-ZIP 创建的 zip 文件,您会看到确实列出了目录:

    $ zip foo.zip -r foo
      adding: foo/ (stored 0%)
      adding: foo/foo.jpg (deflated 84%)
    $ less foo.zip
      Archive:  foo.zip
     Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
    --------  ------  ------- ---- ---------- ----- --------  ----
           0  Stored        0   0% 2013-08-18 14:32 00000000  foo/
      476320  Defl:N    77941  84% 2013-08-18 14:31 55a52268  foo/foo.jpg
    --------          -------  ---                            -------
      476320            77941  84%                            2 files
    

    请注意,目录条目的长度为零并且未压缩。看来您可以通过按名称编写目录来使用 Python 实现相同的目的,但强制它不使用压缩。

    if os.path.isdir(name):
        zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_STORED)
    else:
        zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_DEFLATED)
    

    可能值得确保arcname/ 结尾。

    【讨论】:

      【解决方案6】:

      以下是将整个目录压缩成 zip 文件的一些代码。

      这似乎可以在 Windows 和 linux 上创建 zip 文件。输出 文件似乎可以在 Windows 上正确提取(内置压缩文件夹功能, WinZip 和 7-Zip)和 linux。但是,出现 zip 文件中的空目录 成为一个棘手的问题。下面的解决方案似乎有效,但输出 linux上的“zipinfo”是令人担忧的。也没有设置目录权限 正确用于 zip 存档中的空目录。这似乎需要 一些更深入的研究。

      我从this velocity reviews threadthis python mailing list thread 得到了一些信息。

      请注意,此功能旨在将文件放入 zip 存档中 要么没有父目录,要么只有一个父目录,所以它会修剪任何 文件系统路径中的前导目录,而不是将它们包含在 zip 存档路径。当您只想采取 目录并将其制作成一个zip文件,可以在不同的地方解压 地点。

      关键字参数:

      dirPath -- 要归档的目录的字符串路径。这是唯一的 必需的论据。它可以是绝对的或相对的,但只有一或零 前导目录将包含在 zip 存档中。

      zipFilePath -- 输出 zip 文件的字符串路径。这可以是绝对的 或相对路径。如果 zip 文件已经存在,它将被更新。如果 不,它将被创建。如果您想从头开始替换它,请删除它 在调用此函数之前。 (默认计算为 dirPath + ".zip")

      includeDirInZip -- 布尔值,指示顶级目录是否应该 被包含在档案中或被省略。 (默认为真)

      (请注意,StackOverflow 似乎无法很好地打印我的 python 三重引号字符串,所以我只是将我的文档字符串转换为这里的帖子文本)

      #!/usr/bin/python
      import os
      import zipfile
      
      def zipdir(dirPath=None, zipFilePath=None, includeDirInZip=True):
      
          if not zipFilePath:
              zipFilePath = dirPath + ".zip"
          if not os.path.isdir(dirPath):
              raise OSError("dirPath argument must point to a directory. "
                  "'%s' does not." % dirPath)
          parentDir, dirToZip = os.path.split(dirPath)
          #Little nested function to prepare the proper archive path
          def trimPath(path):
              archivePath = path.replace(parentDir, "", 1)
              if parentDir:
                  archivePath = archivePath.replace(os.path.sep, "", 1)
              if not includeDirInZip:
                  archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1)
              return os.path.normcase(archivePath)
      
          outFile = zipfile.ZipFile(zipFilePath, "w",
              compression=zipfile.ZIP_DEFLATED)
          for (archiveDirPath, dirNames, fileNames) in os.walk(dirPath):
              for fileName in fileNames:
                  filePath = os.path.join(archiveDirPath, fileName)
                  outFile.write(filePath, trimPath(filePath))
              #Make sure we get empty directories as well
              if not fileNames and not dirNames:
                  zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/")
                  #some web sites suggest doing
                  #zipInfo.external_attr = 16
                  #or
                  #zipInfo.external_attr = 48
                  #Here to allow for inserting an empty directory.  Still TBD/TODO.
                  outFile.writestr(zipInfo, "")
          outFile.close()
      

      以下是一些示例用法。请注意,如果您的 dirPath 参数有多个前导目录,则默认情况下仅包含最后一个。传递 includeDirInZip=False 以省略所有前导目录。

      zipdir("foo") #Just give it a dir and get a .zip file
      zipdir("foo", "foo2.zip") #Get a .zip file with a specific file name
      zipdir("foo", "foo3nodir.zip", False) #Omit the top level directory
      zipdir("../test1/foo", "foo4nopardirs.zip")
      

      【讨论】:

        【解决方案7】:

        非常感谢您提供这个有用的功能!我发现它非常有用,因为我也在寻求帮助。但是,也许稍微改变一下它会很有用

        basedir = os.path.dirname(dirpath) + '/'
        

        应该是

        basedir = os.path.dirname(dirpath + '/')
        

        因为发现如果我想压缩位于 'C:\folder\path\notWanted\to\zip\Example' 的文件夹 'Example',

        我进入了 Windows:

        dirpath = 'C:\folder\path\notWanted\to\zip\Example'
        basedir = 'C:\folder\path\notWanted\to\zip\Example/'
        dirname = 'C:\folder\path\notWanted\to\zip\Example\Example\Subfolder_etc'
        

        但我想你的代码应该给出

        dirpath = 'C:\folder\path\notWanted\to\zip\Example'
        basedir = 'C:\folder\path\notWanted\to\zip\Example\'
        dirname = '\Subfolder_etc'
        

        【讨论】:

          【解决方案8】:

          这是我用来压缩文件夹的函数:

          import os
          import os.path
          import zipfile
          
          def zip_dir(dirpath, zippath):
              fzip = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED)
              basedir = os.path.dirname(dirpath) + '/' 
              for root, dirs, files in os.walk(dirpath):
                  if os.path.basename(root)[0] == '.':
                      continue #skip hidden directories        
                  dirname = root.replace(basedir, '')
                  for f in files:
                      if f[-1] == '~' or (f[0] == '.' and f != '.htaccess'):
                          #skip backup files and all hidden files except .htaccess
                          continue
                      fzip.write(root + '/' + f, dirname + '/' + f)
              fzip.close()
          

          【讨论】:

            【解决方案9】:

            当你想创建一个空文件夹时,你可以这样做:

                storage = api.Storage.open("empty_folder.zip","w")
                res = storage.open_resource("hannu//","w")
                storage.close()
            

            文件夹在 wineextractor 中不显示,但是当你提取它时它会显示。

            【讨论】:

              【解决方案10】:

              好的,在我明白你想要什么之后,它就像使用zipfile.write的第二个参数一样简单,你可以使用任何你想要的:

              import zipfile
              myZipFile = zipfile.ZipFile("zip.zip", "w" )
              myZipFile.write("test.py", "dir\\test.py", zipfile.ZIP_DEFLATED )
              

              创建一个压缩文件,其中test.py 将被提取到名为dir 的目录中

              编辑: 我曾经不得不在一个 zip 文件中创建一个空目录:这是可能的。 在上面的代码只是从压缩文件中删除文件 test.py 之后,文件消失了,但空目录仍然存在。

              【讨论】:

              • 是的,这看起来就是我需要的东西。在阅读了 ΤZΩΤZΙΟΥ 的评论后,我现在了解 zip 文件中的“文件夹”是如何工作的。我在相关问题中发现了一些代码,它们也做了我想要的,但我不明白怎么做。我会再做一些实验,然后返回发布我实际使用的代码。 :)
              • 最好的是,它与tarfile 也是一样的,如果你曾经创建一个:) 在tarfile 参数称为arcname 用于存档名称。
              • 要跨平台工作,您需要使用 os.path.join("dir","test.py")
              • 对于目录条目本身(包括空目录),我认为您可以将它们传递给.write,就好像它们是文件一样。但是对目录使用zipfile.ZIP_STORED。我添加了一个包含更多细节的答案。
              • 喜欢你这样做的方式...我一直在使用 for 循环,这需要太多时间
              【解决方案11】:

              这是我运行的编辑代码。它基于上面的代码,取自邮件列表。我添加了导入并制作了一个主要例程。我还减少了对输出文件名的摆弄,以使代码更短。

              #!/usr/bin/env python
              
              import os, zipfile, glob, sys
              
              def addFolderToZip(myZipFile,folder):
                  folder = folder.encode('ascii') #convert path to ascii for ZipFile Method
                  for file in glob.glob(folder+"/*"):
                          if os.path.isfile(file):
                              print file
                              myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED)
                          elif os.path.isdir(file):
                              addFolderToZip(myZipFile,file)
              
              def createZipFile(filename,files,folders):
                  myZipFile = zipfile.ZipFile( filename, "w" ) # Open the zip file for writing 
                  for file in files:
                      file = file.encode('ascii') #convert path to ascii for ZipFile Method
                      if os.path.isfile(file):
                          (filepath, filename) = os.path.split(file)
                          myZipFile.write( file, filename, zipfile.ZIP_DEFLATED )
              
                  for folder in  folders:   
                      addFolderToZip(myZipFile,folder)  
                  myZipFile.close()
                  return (1,filename)
              
              if __name__=="__main__":
                  #put everything in sys.argv[1] in out.zip, skip files
                  print createZipFile("out.zip", [], sys.argv[1])
              

              在我的 Windows 机器上工作时,这段代码运行良好,但没有在 zip 文件中创建任何“文件夹”。至少我记得是这样的。现在在家里,在我的 Linux 机器上,创建的 zip 文件似乎很糟糕:

              $ unzip -l out.zip 
              Archive:  out.zip
                End-of-central-directory signature not found.  Either this file is not
                a zipfile, or it constitutes one disk of a multi-part archive.  In the
                latter case the central directory and zipfile comment will be found on
                the last disk(s) of this archive.
              unzip:  cannot find zipfile directory in one of out.zip or
                      out.zip.zip, and cannot find out.zip.ZIP, period.
              

              我不知道是不是我不小心弄坏了代码,我认为它是一样的。跨平台问题?无论哪种方式,它都与我原来的问题无关;获取 zip 文件中的文件夹。只是想发布我实际运行的代码,而不是我的代码所基于的代码。

              【讨论】:

              • 这是新代码吗?那么它应该是一个新的问题。如果没有用新的事实更新您的问题。这似乎不是答案。
              • sys.argv[1] 是一个字符串。您将其作为folders 传递。当你遍历一个字符串时,你一次只得到一个字母。
              • 将新问题作为问题发布,而不是作为答案发布。
              【解决方案12】:

              一个 zip 文件没有目录结构,它只有一堆路径名和它们的内容。这些路径名应该相对于一个虚构的根文件夹(ZIP 文件本身)。 “../”前缀在 zip 文件中没有明确的含义。

              假设您有一个文件,a,并且您想将它存储在 zip 文件内的“文件夹”中。将文件存储在 zipfile 中时,您所要做的就是在文件名前加上文件夹名称:

              zipi= zipfile.ZipInfo()
              zipi.filename= "folder/a" # this is what you want
              zipi.date_time= time.localtime(os.path.getmtime("a"))[:6]
              zipi.compress_type= zipfile.ZIP_DEFLATED
              filedata= open("a", "rb").read()
              
              zipfile1.writestr(zipi, filedata) # zipfile1 is a zipfile.ZipFile instance
              

              我不知道有任何 ZIP 实现允许在 ZIP 文件中包含 empty 文件夹。我可以想到一个解决方法(在 zip“文件夹”中存储一个 dummy 文件名,在提取时应该忽略该文件名),但不能跨实现移植。

              【讨论】:

              • 我明白了。所以如果我做对了,一个 zip 文件不包含任何文件夹。但是,如果一个文件的名称中有一个路径分隔符,它会在大多数存档管理器中显示为文件夹中的文件吗?并且在解压存档时会以这种方式创建?
              • 正确。这很难做到,因为存档工具正确地转义了文件名中的路径分隔符。但是,您的 python 程序可以强制输入未转义的名称。
              • 在python中创建条目的正确方法是writestr(directory, '')。在 macOS 上,为目录创建零字节条目
              【解决方案13】:

              添加一些导入后,您的代码对我来说运行良好,您如何调用脚本,也许您可​​以告诉我们“..\packed\bin”目录的文件夹结构。

              我使用以下参数调用了您的代码:

              planName='test.zip'
              files=['z.py',]
              folders=['c:\\temp']
              (success,filename)=createZipFile(planName,files,folders)
              

              `

              【讨论】:

              • 使用这些参数调用代码将创建一个 test.zip 文件,其中包含 z.py 和 c:\temp 中的每个文件,但没有文件夹。只是一个包含许多文件的 zip。但我在相关问题中找到了一个答案,似乎可以满足我的要求。将进一步研究那个。
              • 是的,也许你可以举个例子如何调用rhe代码,所以你的错误就出现了。
              • 没有错误。该代码创建一个 zip 文件和所有这些。问题在于我希望在文件解压缩时创建文件夹,或者包含文件夹的 zip 文件取决于你如何看待它。
              猜你喜欢
              • 1970-01-01
              • 2014-10-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多