【问题标题】:Cleaner way to read/gunzip a huge file in python在 python 中读取/压缩一个大文件的更简洁的方法
【发布时间】:2013-01-17 08:05:16
【问题描述】:

所以我有一些相当大的 .gz 文件——解压后每个文件 10 到 20 GB。

我需要遍历它们的每一行,所以我使用的是标准:

import gzip
f = gzip.open(path+myFile, 'r')
for line in f.readlines():
    #(yadda yadda)
f.close()

但是,open()close() 命令都占用了 AGES,占用了 98% 的内存 + CPU。以至于程序退出并将Killed 打印到终端。也许它正在将整个提取的文件加载到内存中?

我现在正在使用类似的东西:

from subprocess import call
f = open(path+'myfile.txt', 'w')
call(['gunzip', '-c', path+myfile], stdout=f)
#do some looping through the file
f.close()
#then delete extracted file

这行得通。但是有更清洁的方法吗?

【问题讨论】:

  • 你确定是 open 而不是 readlines 会永远持续吗?

标签: python gzip subprocess gunzip


【解决方案1】:

看看pandas, in particular IO tools。它们在读取文件时支持 gzip 压缩,您可以分块读取文件。此外,pandas 速度非常快,内存效率也很高。

由于我从未尝试过,我不知道压缩和读取块的效果如何,但可能值得一试

【讨论】:

  • gzip.open 具有完美的缓冲功能,因此您无需显式读取块;只需使用普通的类似文件的 API 以最合适的方式读取它(for line in f:,或for row in csv.reader(f),甚至readlines,带有大小提示而不是没有参数)。而且它的速度也非常快,内存效率也很高。据我所知,由于readlines,OP 的代码只是一个内存占用,而且它只是因为占用内存而变慢。
【解决方案2】:

我 99% 确定您的问题不在gzip.open(),而是在readlines()

正如the documentation 解释的那样:

f.readlines() 返回一个包含文件中所有数据行的列表。

显然,这需要读取和解压整个文件,并建立一个绝对庞大的列表。

最有可能的是,实际上是 malloc 调用来分配永远占用的所有内存。然后,在这个作用域的末尾(假设你使用的是 CPython),它必须对整个巨大的列表进行 GC,这也将花费很长时间。

你几乎不想使用readlines。除非您使用的是非常旧的 Python,否则请执行以下操作:

for line in f:

file 是一个可迭代的完整行,就像 readlines 返回的 list — 除了它实际上不是 list,它通过读取缓冲区动态生成更多行。因此,在任何给定时间,您将只有一行和几个缓冲区,每个缓冲区大约 10MB,而不是 25GB list。并且读取和解压将分散在循环的整个生命周期中,而不是一次完成。

通过快速测试,使用 3.5GB gzip 文件,gzip.open() 实际上是即时的,for line in f: pass 需要几秒钟,gzip.close() 实际上是即时的。但是如果我这样做for line in f.readlines(): pass,则需要……好吧,我不确定要多长时间,因为大约一分钟后,我的系统进入了swap thrashing hell,我不得不强行杀死解释器以使其响应任何内容……


自从这个答案以来已经出现了十几次,我写了this blog post 来解释更多。

【讨论】:

  • @shihpeng for line in f: 是一个pythonic和正确的答案。您还有其他信息吗?
  • @FirefighterBlu3 您指的是一个有 4 年历史的评论,该评论指的是一个被误导并被回答者删除的答案。将其标记为不再需要或忽略它可能比回复它更好。 (如果您无法阅读已删除的答案,shihpeng 的问题是他实际上没有文本数据,而是二进制数据恰好可以到达许多兆字节而没有\x0a 字节在任何地方。答案是不读取二进制数据作为文本......)
猜你喜欢
  • 2012-07-14
  • 1970-01-01
  • 2019-11-09
  • 2015-01-12
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 2017-03-10
  • 2015-01-07
相关资源
最近更新 更多