15

Pythonを使用してzipアーカイブを抽出する方法を知っていますが、その抽出の進行状況をパーセンテージで正確に表示するにはどうすればよいですか?

4

3 に答える 3

14

を使用することをお勧めします。次のようにtqdmインストールできます。pip

pip install tqdm

次に、次のように直接使用できます。

>>> from tqdm import 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]
于 2019-07-10T12:19:32.977 に答える
8

extractメソッドはこれに対するコールバックを提供しないため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()

getinfo(member)メンバーがZipInfoオブジェクトでない場合は、メンバーが名前からZipInfoオブジェクトに変換されます。

于 2010-12-03T01:29:13.633 に答える
1

これを見て少し遅れてすみません。同様の問題があり、に相当するものが必要zipfile.Zipfile.extractallです。tqdm>=4.40.0(1年以上前にリリースした)場合は、次のようにします。

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)
于 2020-12-30T21:34:10.833 に答える