我最近意识到.tar.gz
和.zip
存档文件都不支持对它们在python中包含的文件进行快速迭代。我来详细说明一下。
我收集了大量的文件。统计数据如下:
- 文件数:4'810'289
- 目录数:402'212
tar.gz
归档文件为9GB.zip
归档文件大小为16GB- 未压缩数据重190GB
使用.tar.gz
方法,我认为可以通过pickle下面代码的结果来创建索引:
with tarfile.open(self.file.path, "r:gz") as tar:
return tar.getmembers()
结果是一个大约2GB的pickle文件,但问题是您必须读取整个存档,以获取您想要提取的每个成员。实际上,之后运行tar.extractfile(member)
对每个成员来说都需要几分钟!所以这里没有。
使用.zip
方法略有不同,但仍然不能实现对文件的快速迭代。只要你执行:
from zipfile import ZipFile
zip = ZipFile(file_path)
模块似乎加载一个完整的文件到RAM中,因为解释器挂起大约5分钟,最终使用19GB的RAM(看top
),只要你保持zip
对象。之后zip.infolist()
和zip.open(member).read()
非常快。所以至少比.tar.gz
好。
在python中是否有一个多文件压缩归档格式,能够一个接一个地迭代文件,而无需加载完整文件,构建冗长的索引或每次读取整个文件?
谢谢。
我没有看到ZipFile
行为。这是一个16gb的zip文件,大约有11,000个条目。内存使用量远不及zip文件的大小:
Python 3.9.6 (default, Sep 26 2022, 11:37:49)
[Clang 14.0.0 (clang-1400.0.29.202)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import tracemalloc
>>> tracemalloc.start()
>>> print(tracemalloc.get_traced_memory())
(8797, 11854)
>>> from zipfile import ZipFile
>>> print(tracemalloc.get_traced_memory())
(1429688, 1448932)
>>> zip = ZipFile("/Users/madler/Downloads/iCloud Photos Part 12 of 12.zip")
>>> print(tracemalloc.get_traced_memory())
(9208481, 10508727)
>>> info = zip.infolist()
>>> len(info)
11341
>>> print(tracemalloc.get_traced_memory())
(9210488, 10508727)
据我所知,所有的命令都立即执行。
我希望内存使用与zip文件中的条目数成正比,而不是与zip文件大小成正比。ZipFile
应该只是将zip文件的中心目录读入内存。在我的例子中,我看到每个条目大约有700字节的内存。据推测,如果文件名的长度相当,那么您的文件大约需要3 GB。这是一个不错的内存块,但肯定不是19gb。