python 解压 -- 极慢?
有人能解释一下这个谜团吗?
我创建了一个大约37MB的二进制文件。在Ubuntu系统中,用终端压缩这个文件,花了不到1秒钟。然后我尝试用Python编程来压缩(使用zipfile模块),也差不多花了1秒钟。
接着,我尝试解压我创建的这个zip文件。在Ubuntu中,用终端解压也花了不到1秒钟。
但是在Python中,解压的代码(同样使用zipfile模块)却花了将近37秒!有人知道为什么吗?
4 个回答
这里有一些选择:
- 可以使用
subprocess
这个工具,把任务交给外部工具来处理。你可以直接把数据传给它。 - czipfile,不过这个项目似乎已经不再维护了(最后一次发布是在2010年)。最近有一个分支是 ziyuang/czipfile(最后更新是在2019年)。
- PyTorch 有一个内部的原生工具
torch._C.PyTorchFileReader
,可以用来读取zip文件,具体可以看看torch.load
的逻辑和_open_zipfile_reader
。目前这个工具不支持任意的zip文件,但我觉得只需要稍微调整一下就能支持了。 - libzip.py(2023年)是一个基于 libzip 的ctypes封装。不过这个工具似乎不太有人知道?
我不知道你用什么代码来解压你的文件,但以下这个方法对我来说很好用:我创建了一个名为“test.zip”的压缩包,里面只包含一个文件“file1”,然后用下面的Python脚本把“file1”从压缩包里提取出来:
from zipfile import ZipFile, ZIP_DEFLATED
zip = ZipFile("test.zip", mode='r', compression=ZIP_DEFLATED, allowZip64=False)
data = zip.read("file1")
print len(data)
这个过程几乎不需要时间:我试了一个37MB的输入文件,压缩后变成了15MB的zip文件。在这个例子中,我的MacBook Pro上运行这个Python脚本只花了0.346秒。也许在你的情况下,37秒是因为你对数据做了其他操作?
我之前也在用Python解压缩zip文件时遇到了一些困难,感觉那种“创建ZipFile对象,循环遍历它的.namelist(),读取文件然后写入文件系统”的低级方法不太像Python的风格。所以我开始研究zipfile对象,我觉得这个部分的文档写得不太好,涵盖了所有对象的方法:
>>> from zipfile import ZipFile
>>> filepath = '/srv/pydocfiles/packages/ebook.zip'
>>> zip = ZipFile(filepath)
>>> dir(zip)
['NameToInfo', '_GetContents', '_RealGetContents', '__del__', '__doc__', '__enter__', '__exit__', '__init__', '__module__', '_allowZip64', '_didModify', '_extract_member', '_filePassed', '_writecheck', 'close', 'comment', 'compression', 'debug', 'extract', 'extractall', 'filelist', 'filename', 'fp', 'getinfo', 'infolist', 'mode', 'namelist', 'open', 'printdir', 'pwd', 'read', 'setpassword', 'start_dir', 'testzip', 'write', 'writestr']
这里有个“extractall”方法,跟tarfile的extractall用法一样!(在Python 2.6和2.7上可以用,但在2.5上不行)
接下来是性能方面的问题;我有一个文件ebook.zip,大小84.6 MB(大部分是pdf文件),解压后的文件夹是103 MB,是在MacOSx 10.5下用默认的“归档工具”压缩的。所以我用Python的timeit模块做了同样的测试:
>>> from timeit import Timer
>>> t = Timer("filepath = '/srv/pydocfiles/packages/ebook.zip'; \
... extract_to = '/tmp/pydocnet/build'; \
... from zipfile import ZipFile; \
... ZipFile(filepath).extractall(path=extract_to)")
>>>
>>> t.timeit(1)
1.8670060634613037
在一台负载很重的机器上,内存有90%都被其他应用占用的情况下,解压缩花了不到2秒钟。
希望这对某些人有帮助。