【问题标题】:zip file and avoid directory structurezip文件并避免目录结构
【发布时间】:2015-01-16 19:52:31
【问题描述】:

我有一个压缩文件的 Python 脚本 (new.txt):

tofile =  "/root/files/result/"+file
targetzipfile = new.zip # This is how I want my zip to look like
zf = zipfile.ZipFile(targetzipfile, mode='w')
try:
    #adding to archive
    zf.write(tofile)
finally:
    zf.close()

当我这样做时,我得到了 zip 文件。但是当我尝试解压缩文件时,我会在与文件路径相对应的一系列目录中获取文本文件,即我在result 目录中看到一个名为root 的文件夹以及其中的更多目录,即我有

/root/files/result/new.zip

当我解压缩 new.zip 时,我的目录结构看起来像

/root/files/result/root/files/result/new.txt

有没有一种方法可以让我在解压缩时只得到new.txt

换句话说,我有/root/files/result/new.zip,当我解压缩new.zip时,它应该看起来像

/root/files/results/new.txt

【问题讨论】:

    标签: python zip


    【解决方案1】:

    zipfile.write() 方法采用可选的arcname 参数,指定压缩文件中的文件名

    我认为您需要对目标进行修改,否则会复制目录。使用 :arcname 来避免它。试试这样:

    import os
    import zipfile
    
    def zip(src, dst):
        zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED)
        abs_src = os.path.abspath(src)
        for dirname, subdirs, files in os.walk(src):
            for filename in files:
                absname = os.path.abspath(os.path.join(dirname, filename))
                arcname = absname[len(abs_src) + 1:]
                print 'zipping %s as %s' % (os.path.join(dirname, filename),
                                            arcname)
                zf.write(absname, arcname)
        zf.close()
    
    zip("src", "dst")
    

    【讨论】:

    • 我不明白为什么您需要指定 arcname 以避免它遍历所有父文件夹直到根目录,如果我提供文件路径,为什么不只考虑文件?
    • 你可以更改 arcname = absname[len(abs_src) + 1:] 为 arcname = os.path.basename(absname)
    【解决方案2】:
    zf.write(tofile)
    

    改变

    zf.write(tofile, zipfile_dir)
    

    例如

    zf.write("/root/files/result/root/files/result/new.txt", "/root/files/results/new.txt")
    

    【讨论】:

    • @user34551743,太棒了!
    【解决方案3】:

    为了说明最清楚,

    目录结构:

    /Users
     └── /user
     .    ├── /pixmaps
     .    │    ├── pixmap_00.raw
     .    │    ├── pixmap_01.raw
          │    ├── /jpeg
          │    │    ├── pixmap_00.jpg
          │    │    └── pixmap_01.jpg
          │    └── /png
          │         ├── pixmap_00.png
          │         └── pixmap_01.png
          ├── /docs
          ├── /programs
          ├── /misc
          .
          .
          .
    

    感兴趣的目录:/Users/user/pixmaps

    第一次尝试

    import os
    import zipfile
    
    TARGET_DIRECTORY = "/Users/user/pixmaps"
    ZIPFILE_NAME = "CompressedDir.zip"
    
    def zip_dir(directory, zipname):
        """
        Compress a directory (ZIP file).
        """
        if os.path.exists(directory):
            outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
    
            for dirpath, dirnames, filenames in os.walk(directory):
                for filename in filenames:
    
                    filepath   = os.path.join(dirpath, filename)
                    outZipFile.write(filepath)
    
            outZipFile.close()
    
    
    
    
    if __name__ == '__main__':
        zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
    

    ZIP 文件结构:

    CompressedDir.zip
    .
    └── /Users
         └── /user
              └── /pixmaps
                   ├── pixmap_00.raw
                   ├── pixmap_01.raw
                   ├── /jpeg
                   │    ├── pixmap_00.jpg
                   │    └── pixmap_01.jpg
                   └── /png
                        ├── pixmap_00.png
                        └── pixmap_01.png
    

    避免完整的目录路径

    def zip_dir(directory, zipname):
        """
        Compress a directory (ZIP file).
        """
        if os.path.exists(directory):
            outZipFile = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
    
            # The root directory within the ZIP file.
            rootdir = os.path.basename(directory)
    
            for dirpath, dirnames, filenames in os.walk(directory):
                for filename in filenames:
    
                    # Write the file named filename to the archive,
                    # giving it the archive name 'arcname'.
                    filepath   = os.path.join(dirpath, filename)
                    parentpath = os.path.relpath(filepath, directory)
                    arcname    = os.path.join(rootdir, parentpath)
    
                    outZipFile.write(filepath, arcname)
    
        outZipFile.close()
    
    
    
    
    if __name__ == '__main__':
        zip_dir(TARGET_DIRECTORY, ZIPFILE_NAME)
    

    ZIP 文件结构:

    CompressedDir.zip
    .
    └── /pixmaps
         ├── pixmap_00.raw
         ├── pixmap_01.raw
         ├── /jpeg
         │    ├── pixmap_00.jpg
         │    └── pixmap_01.jpg
         └── /png
              ├── pixmap_00.png
              └── pixmap_01.png
    

    【讨论】:

    • 在第二个程序中,我认为outZipFile.close() 应该是inside if 块。
    【解决方案4】:

    查看 Zipfile.write 的文档。

    ZipFile.write(filename[, arcname[, compress_type]]) 写入文件 命名文件名到档案,给它档案名称 arcname(由 默认情况下,这将与文件名相同,但没有驱动器号 并删除了前导路径分隔符)

    https://docs.python.org/2/library/zipfile.html#zipfile.ZipFile.write

    尝试以下方法:

    import zipfile
    import os
    filename = 'foo.txt'
    
    # Using os.path.join is better than using '/' it is OS agnostic
    path = os.path.join(os.path.sep, 'tmp', 'bar', 'baz', filename)
    zip_filename = os.path.splitext(filename)[0] + '.zip'
    zip_path = os.path.join(os.path.dirname(path), zip_filename)
    
    # If you need exception handling wrap this in a try/except block
    with zipfile.ZipFile(zip_path, 'w') as zf:
        zf.write(path, zip_filename)
    

    底线是,如果您不提供存档名称,则文件名将用作存档名称,它将包含文件的完整路径。

    【讨论】:

      【解决方案5】:

      您可以使用以下方法仅隔离源文件的文件名:

      name_file_only= name_full_path.split(os.sep)[-1]
      

      例如,如果name_full_path/root/files/results/myfile.txt,那么name_file_only 将是myfile.txt。要将 myfile.txt 压缩到存档 zf 的根目录,您可以使用:

      zf.write(name_full_path, name_file_only)
      

      【讨论】:

      • 如果你有一个不存在的不同问题,那么我认为你应该问那个问题,然后回答你自己的问题。当他人搜索更相关的问题时,您将帮助他人(甚至可能是您自己)。
      【解决方案6】:

      write 方法中的 arcname 参数指定 zipfile 中文件的名称:

      import os
      import zipfile
      
      # 1. Create a zip file which we will write files to
      zip_file = "/home/username/test.zip"
      zipf = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
      
      # 2. Write files found in "/home/username/files/" to the test.zip
      files_to_zip = "/home/username/files/"
      for file_to_zip in os.listdir(files_to_zip):
      
          file_to_zip_full_path = os.path.join(files_to_zip, file_to_zip)
      
          # arcname argument specifies what will be the name of the file inside the zipfile
          zipf.write(filename=file_to_zip_full_path, arcname=file_to_zip)
      
      zipf.close()
      

      【讨论】:

      • 在所有答案中,你的答案是最简单的,很快就让我理解了。谢谢!
      【解决方案7】:

      我们可以用这个

      import os
      # single File
      os.system(f"cd {destinationFolder} && zip fname.zip fname") 
      # directory
      os.system(f"cd {destinationFolder} && zip -r folder.zip folder") 
      

      对我来说,这是有效的。

      【讨论】:

        【解决方案8】:

        这比预期的要简单得多,我使用参数“arcname”将模块配置为“file_to_be_zipped.txt”,因此文件夹不会出现在我的最终压缩文件中:

        mmpk_zip_file = zipfile.ZipFile("c:\\Destination_folder_name\newzippedfilename.zip", mode='w', compression=zipfile.ZIP_DEFLATED)
        mmpk_zip_file.write("c:\\Source_folder_name\file_to_be_zipped.txt", "file_to_be_zipped.txt")
        mmpk_zip_file.close()
        

        【讨论】:

          【解决方案9】:

          指定write方法的arcname输入如下:

          tofile =  "/root/files/result/"+file
          NewRoot = "files/result/"
          zf.write(tofile, arcname=tofile.split(NewRoot)[1])
          

          更多信息:

          ZipFile.write(filename, arcname=None, compress_type=None, 压缩级别=无) https://docs.python.org/3/library/zipfile.html

          【讨论】:

            【解决方案10】:

            我遇到了同样的问题,我用writestr 解决了它。你可以这样使用它:

            zipObject.writestr(<filename> , <file data, bytes or string>)

            【讨论】:

              【解决方案11】:

              如果您想以优雅的方式使用pathlib,您可以这样使用:

              from pathlib import Path
              import zipfile
              
              def zip_dir(path_to_zip: Path):
                  zip_file = Path(path_to_zip).with_suffix('.zip')
                  z = zipfile.ZipFile(zip_file, 'w', zipfile.ZIP_DEFLATED)
                  for f in list(path_to_zip.rglob('*.*')):
                      z.write(f, arcname=f.relative_to(path_to_zip))
              

              【讨论】:

                【解决方案12】:

                为了摆脱绝对路径,我想出了这个:

                def create_zip(root_path, file_name, ignored=[], storage_path=None):
                    """Create a ZIP
                    
                    This function creates a ZIP file of the provided root path.
                    
                    Args:
                        root_path (str): Root path to start from when picking files and directories.
                        file_name (str): File name to save the created ZIP file as.
                        ignored (list): A list of files and/or directories that you want to ignore. This
                                        selection is applied in root directory only.
                        storage_path: If provided, ZIP file will be placed in this location. If None, the
                                        ZIP will be created in root_path
                    """
                    if storage_path is not None:
                        zip_root = os.path.join(storage_path, file_name)
                    else:
                        zip_root = os.path.join(root_path, file_name)
                        
                    zipf = zipfile.ZipFile(zip_root, 'w', zipfile.ZIP_DEFLATED)
                    def iter_subtree(path, layer=0):
                        # iter the directory
                        path = Path(path)
                        for p in path.iterdir():
                            if layer == 0 and p.name in ignored:
                                continue
                            zipf.write(p, str(p).replace(root_path, '').lstrip('/'))
                            
                            if p.is_dir():
                                iter_subtree(p, layer=layer+1)
                
                    iter_subtree(root_path)
                    zipf.close()
                

                也许这不是最优雅的解决方案,但这是可行的。如果我们在向write() 方法提供文件名时只使用p.name,那么它不会创建正确的目录结构。

                此外,如果需要忽略从根路径中选择的目录或文件,这也会忽略这些选择。

                【讨论】:

                  猜你喜欢
                  • 2012-03-31
                  • 2022-12-06
                  • 1970-01-01
                  • 2014-11-25
                  • 2021-01-15
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-09-20
                  • 1970-01-01
                  相关资源
                  最近更新 更多