【问题标题】:Extract files from zip without keeping the structure using python ZipFile?使用python ZipFile从zip中提取文件而不保留结构?
【发布时间】:2011-06-22 11:35:56
【问题描述】:

我尝试从一个文件夹中包含子文件夹的 .zip 中提取所有文件。我希望子文件夹中的所有文件仅提取到一个文件夹中,而不保留原始结构。目前,我提取所有文件,将文件移动到一个文件夹,然后删除以前的子文件夹。同名文件会被覆盖。

可以在写文件之前做吗?

这是一个结构示例:

my_zip/file1.txt
my_zip/dir1/file2.txt
my_zip/dir1/dir2/file3.txt
my_zip/dir3/file4.txt

最后我希望:

my_dir/file1.txt
my_dir/file2.txt
my_dir/file3.txt
my_dir/file4.txt

我可以在这段代码中添加什么?

import zipfile
my_dir = "D:\\Download\\"
my_zip = "D:\\Download\\my_file.zip"

zip_file = zipfile.ZipFile(my_zip, 'r')
for files in zip_file.namelist():
    zip_file.extract(files, my_dir)
zip_file.close()

如果我从 zip_file.namelist() 重命名文件路径,则会出现以下错误:

KeyError: "There is no item named 'file2.txt' in the archive"

【问题讨论】:

    标签: python extract unzip zipfile


    【解决方案1】:

    这会打开 zip 存档成员的文件句柄,提取文件名并将其复制到目标文件(ZipFile.extract 就是这样工作的,无需处理子目录)。

    import os
    import shutil
    import zipfile
    
    my_dir = r"D:\Download"
    my_zip = r"D:\Download\my_file.zip"
    
    with zipfile.ZipFile(my_zip) as zip_file:
        for member in zip_file.namelist():
            filename = os.path.basename(member)
            # skip directories
            if not filename:
                continue
        
            # copy file (taken from zipfile's extract)
            source = zip_file.open(member)
            target = open(os.path.join(my_dir, filename), "wb")
            with source, target:
                shutil.copyfileobj(source, target)
    

    【讨论】:

    • 我正在使用它,但现在元数据已经消失了。您知道保存元数据的方法吗? (创建日期时间)
    • 这很好用!但是有没有办法包含子目录?该子目录被正常处理并被提取到该文件夹​​中?
    【解决方案2】:

    可以遍历ZipFile.infolist()。在返回的ZipInfo 对象上,您可以操作filename 以删除目录部分,最后将其解压缩到指定目录。

    import glob
    import zipfile
    import shutil
    import os
    
    my_dir = "D:\\Download\\"
    my_zip = "D:\\Download\\my_file.zip"
    
    with zipfile.ZipFile(my_zip) as zip:
        for zip_info in zip.infolist():
            if zip_info.filename[-1] == '/':
                continue
            zip_info.filename = os.path.basename(zip_info.filename)
            zip.extract(zip_info, my_dir)
    

    【讨论】:

    • 恕我直言,比接受的答案更容易,并且如果文件名过滤器经过调整,也适用于子目录,例如仅将单个子目录提取到目标目录。
    • 我也更喜欢这个例子,因为只需在文件信息上使用 string.replace 方法然后提取就可以将目录包含在文件名中。 zip_info.filename = zip_info.filename.replace('/','').replace(':','').replace('?','')
    • 这很好用 - 注意 Windows 与 *nix 中的斜线差异。
    【解决方案3】:

    只需提取到内存中的字节,计算文件名,然后自己写在那里, 而不是让库来做——大多数情况下,只需使用“read()”而不是“extract()”方法:

    Python 3.6+ 更新(2020) - 与原始答案相同的代码,但使用 pathlib.Path,可简化文件路径操作和其他操作(如“write_bytes”)

    from pathlib import Path
    import zipfile
    import os
    
    my_dir = Path("D:\\Download\\")
    my_zip = my_dir / "my_file.zip"
    
    zip_file = zipfile.ZipFile(my_zip, 'r')
    for files in zip_file.namelist():
        data = zip_file.read(files, my_dir)
        myfile_path = my_dir / Path(files.filename).name
        myfile_path.write_bytes(data)
    zip_file.close()
    

    答案中的原始代码没有 pathlib:

    import zipfile
    import os
    
    my_dir = "D:\\Download\\"
    my_zip = "D:\\Download\\my_file.zip"
    
    zip_file = zipfile.ZipFile(my_zip, 'r')
    for files in zip_file.namelist():
        data = zip_file.read(files, my_dir)
        # I am almost shure zip represents directory separator
        # char as "/" regardless of OS, but I  don't have DOS or Windos here to test it
        myfile_path = os.path.join(my_dir, files.split("/")[-1])
        myfile = open(myfile_path, "wb")
        myfile.write(data)
        myfile.close()
    zip_file.close()
    

    【讨论】:

    • 谢谢。我必须添加一个例外以避免目录 \ 在 myfile_path 中并只保留文件。
    【解决方案4】:

    the solution of Gerhard Götz 类似的概念,但适用于提取单个文件而不是整个 zip:

    with ZipFile(zipPath, 'r') as zipObj:
        zipInfo = zipObj.getinfo(path_in_zip))
        zipInfo.filename = os.path.basename(destination)
        zipObj.extract(zipInfo, os.path.dirname(os.path.realpath(destination)))
    

    【讨论】:

      【解决方案5】:

      如果您遇到 badZipFile 错误。您可以使用 7zip 子进程解压缩存档。假设你已经安装了 7zip 然后使用下面的代码。

      import subprocess
      my_dir = destFolder #destination folder
      my_zip = destFolder + "/" + filename.zip #file you want to extract
      ziploc = "C:/Program Files/7-Zip/7z.exe" #location where 7zip is installed
      cmd = [ziploc, 'e',my_zip ,'-o'+ my_dir ,'*.txt' ,'-r' ] 
      #extracting only txt files and from all subdirectories
      sp = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-20
        • 1970-01-01
        • 2015-04-05
        • 2012-04-06
        相关资源
        最近更新 更多