Python 解压缩 -- 速度极慢?

8

有人能解释以下这个谜团吗?

我创建了一个约37[MB]大小的二进制文件。在Ubuntu终端中压缩它只需要不到1秒钟的时间。然后我尝试了Python:使用zipfile模块进行编程压缩也大约需要1秒钟的时间。

然后我尝试解压缩我创建的zip文件。在Ubuntu终端中,这只需要不到1秒钟的时间。

在Python中,解压缩的代码(使用zipfile模块)运行需要接近37秒钟的时间!有什么想法吗?


5
你能否发布你压缩文件的部分?这样我们可以提供更准确的评论。 - Utku Zihnioglu
1
@TomMD:实际上并不是这样,因为它取决于zlib,至少在文件实际压缩时是这样的。实际的解压缩是由本地代码完成的。值得比较一下当zip文件没有被压缩时的解压时间,看看效果是否来自解释。 - Chinmay Kanchi
@chinmay 发帖人没有说他是如何调用“zip”的,所以我不想假设任何东西。但很高兴知道普通的Python {,un}zip是一个zlib绑定,谢谢! - Thomas M. DuBuisson
4
也许你没有有效地处理未压缩数据流。由于内存分配和交换,将一个大小为37 MB的字符串加载到内存中肯定需要很长时间。你应该直接将输出发送到文件中。你如何使用“zipfile”模块来解压缩压缩文件? - scoffey
1
@scoffey:我很难相信内存分配/交换会花费那么长时间。即使在Python中,37 MB也微不足道。 - hammar
显示剩余2条评论
4个回答

2

我曾经也遇到过使用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下默认使用"Archive Utility"进行压缩。因此,我使用了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秒钟就能完成。

希望这对某些人有所帮助。


哇,zipfile对象文档在我回答后的一天就更新了docs.python.org。也许这是某种输出问题,或者Python正在做得非常好! - kirpit
不错的信息!但是如果我们需要访问一些文件,或者对它们进行某种处理而不仅仅是解压缩,恐怕这并没有太大帮助 :( - MarioVilas

0

我不知道你用什么代码来解压缩文件,但是以下代码对我有效:在创建一个只包含一个文件“file1”的zip归档文件“test.zip”之后,下面的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归档文件。在这个例子中,Python脚本在我的MacBook Pro上只花费了0.346秒。也许在你的情况下,这37秒是由于你对数据做了什么而导致的?

3
只读取一个文件很容易,但是包含许多小压缩文件的大型zip归档文件对我来说运行极慢。也许是因为在zip内查找文件的效率不高? - MarioVilas

0

我们可以使用Ubuntu在Python中提供的zip功能而不是使用Python模块。我会使用这个功能,因为有时Python的zip会失败。

import os

filename = test
os.system('7z a %s.zip %s'% (filename, filename))

你应该使用str.format()而不是%格式化,例如os.system('7z a {0}.zip {0}'.format(filename))。正如他们在文档中提到的那样,它将来会被移除,我相信它已经在3+中被移除了。 - thegrinner
6
错误。这种方法应该尽量避免,而应该使用 import subprocess; subprocess.call(['7z', 'a', filename+'.zip', filename])。如果文件名包含空格或换行符会发生什么? - glglgl

0
一些选项:
- 使用`subprocess`将其推迟到某个外部工具。您可以直接将数据传输给它。 - czipfile,但似乎不再维护(最后发布于2010年)。一个相对较新的分支是ziyuang/czipfile(最后更新于2019年)。 - PyTorch具有内部原生的`torch._C.PyTorchFileReader`,可以读取zip文件,请参阅`torch.load`逻辑和`_open_zipfile_reader`。目前不支持任意zip文件,但我认为只需要进行轻微调整即可支持。 - libzip.py(2023)是对libzip的ctypes包装器。但似乎非常不为人知?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接