Извлечь ZipFile с помощью Python, отобразить процент выполнения?

Я знаю, как извлечь zip-архив с помощью Python, но как именно отображать ход этого извлечения в процентах?


person Zac Brown    schedule 03.12.2010    source источник
comment
Какой графический фреймворк вы планируете использовать?   -  person S.Lott    schedule 03.12.2010
comment
Ткинтер, если ты об этом. Все, что мне нужно, это иметь возможность отображать процент текста.   -  person Zac Brown    schedule 03.12.2010
comment
Несколько грязный обходной путь — порождать извлечение в отдельном процессе, отслеживать файлы, извлекаемые из основного потока, суммировать их размеры и делить на ZipInfo.file_size   -  person Novikov    schedule 03.12.2010


Ответы (3)


метод извлечения не обеспечивает обратный вызов для этого, поэтому нужно было бы использовать getinfo, чтобы получить несжатый размер e, а затем открыть файл, прочитанный из него в блоках, и записать его в то место, куда вы хотите, чтобы файл пошел, и обновить процент, также нужно будет восстановить mtime, если это требуется, например:

import zipfile
z = zipfile.ZipFile(some_source)
entry_info = z.getinfo(entry_name)
i = z.open(entry_name)
o = open(target_name, 'w')
offset = 0
while True:
    b = i.read(block_size)
    offset += len(b)
    set_percentage(float(offset)/float(entry_info.file_size) * 100.)
    if b == '':
        break
    o.write(b)
i.close()
o.close()
set_attributes_from(entry_info)

это извлекает от entry_name до target_name


большая часть этого также делается shutil.copyfileobj, но у него также нет обратного вызова для прогресса

источник вызова метода ZipFile.extract _extract_member использует:

source = self.open(member, pwd=pwd)
target = file(targetpath, "wb")
shutil.copyfileobj(source, target)
source.close()
target.close()

где элемент был преобразован из имени в объект ZipInfo с помощью getinfo(member), если он не был объектом ZipInfo

person Dan D.    schedule 03.12.2010
comment
Окей круто. Мне это нравится. Единственное, в моем архиве есть папки, но он их почему-то не распаковывает. Он вызывает исключение о том, что файл не существует. - person Zac Brown; 03.12.2010
comment
папки не существуют в zip-файлах, так как имена записей файлов являются путями, т.е. some/path/to/some/file будет именем файла, а для каталогов нет записей - person Dan D.; 03.12.2010
comment
Я понял. Я использовал метод извлечения в модуле zipfile... вместе с некоторым использованием модуля ОС. Спасибо. - person Zac Brown; 03.12.2010
comment
Я не совсем понимаю ваш пример выше. Где именно происходит добыча? - person Zac Brown; 03.12.2010

Я предлагаю использовать tqdm, вы можете установить его с помощью pip следующим образом:

pip install tqdm

Затем вы можете использовать его напрямую так:

>>> with zipfile.ZipFile(some_source) as zf:
...     for member in tqdm(zf.infolist(), desc='Extracting '):
...         try:
...             zf.extract(member, target_path)
...         except zipfile.error as e:
...             pass

Это произведет что-то вроде этого:

Extracting : 100%|██████████| 60.0k/60.0k [14:56<00:00, 66.9File/s]
person Anwarvic    schedule 10.07.2019
comment
Можно ли получить процентное значение от tqdm, чтобы я мог реализовать свой индикатор выполнения, как графический интерфейс Windows, обновив его значение? т. е. для отображения пользовательского хода распаковки zip-файла. - person Phani Rithvij; 01.03.2020
comment
Если вам нужен только процент, вам не нужен tqdm. Вы можете легко найти процент, зная индекс файла. Например, предположим, что у вас есть 100 файлов, и сейчас вы извлекаете 4-й файл, значит, вы сделали 4%. Простой!! - person Anwarvic; 01.03.2020
comment
@Anwarvic, если у меня есть файл размером 1 100 МБ и несколько файлов 99 КиБ, то это работает совсем не так ... - person Yamirui; 20.09.2020

Извините, что немного поздно увидел это. Была похожая проблема, нужен эквивалент zipfile.Zipfile.extractall. Если у вас есть tqdm>=4.40.0 (которую я выпустил больше года назад), то:

from os import fspath
from pathlib import Path
from shutil import copyfileobj
from zipfile import ZipFile
from tqdm.auto import tqdm  # could use from tqdm.gui import tqdm
from tqdm.utils import CallbackIOWrapper

def extractall(fzip, dest, desc="Extracting"):
    """zipfile.Zipfile(fzip).extractall(dest) with progress"""
    dest = Path(dest).expanduser()
    with ZipFile(fzip) as zipf, tqdm(
        desc=desc, unit="B", unit_scale=True, unit_divisor=1024,
        total=sum(getattr(i, "file_size", 0) for i in zipf.infolist()),
    ) as pbar:
        for i in zipf.infolist():
            if not getattr(i, "file_size", 0):  # directory
                zipf.extract(i, fspath(dest))
            else:
                with zipf.open(i) as fi, open(fspath(dest / i.filename), "wb") as fo:
                    copyfileobj(CallbackIOWrapper(pbar.update, fi), fo)
person casper.dcl    schedule 30.12.2020