用Python提取Zip文件,如何显示进度百分比?
我知道怎么用Python来解压一个zip压缩包,但我想知道怎么才能把解压的进度显示成百分比呢?
5 个回答
3
抱歉回复得有点晚。我遇到过类似的问题,需要一个和 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)
20
我建议你使用 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]
10
这个提取方法没有提供回调功能,所以你需要用 getinfo
来获取未压缩的文件大小。然后,你需要分块读取文件,并把它写到你想要放置的地方,同时更新进度百分比。如果需要的话,还得恢复文件的修改时间。下面是一个例子:
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 对象的话。