Извлекать файлы из zip без сохранения структуры, используя python ZipFile? - PullRequest
37 голосов
/ 07 февраля 2011

Я пытаюсь извлечь все файлы из .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"

Ответы [ 5 ]

51 голосов
/ 07 февраля 2011

Это открывает файловые дескрипторы членов 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 = file(os.path.join(my_dir, filename), "wb")
        with source, target:
            shutil.copyfileobj(source, target)
12 голосов
/ 04 декабря 2017

Можно выполнить итерацию по 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)
8 голосов
/ 07 февраля 2011

Просто извлеките в байты в памяти, вычислите имя файла и запишите его там самостоятельно, вместо того, чтобы позволить библиотеке делать это - в основном, просто используйте метод read () вместо метода extract ():

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()
1 голос
/ 12 февраля 2019

Концепция, аналогичная решению Герхарда Гетца , но адаптированная для извлечения отдельных файлов вместо всего 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)))
0 голосов
/ 31 января 2019

В случае, если вы получаете ошибку badZipFile. Вы можете распаковать архив, используя 7zip sub process. при условии, что вы установили 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)
...