我应该使用python处理庞大的bz2-文件(5+ GB)。使用我的实际代码,我总是会遇到内存错误。我读到某个地方可以使用sqlite3处理该问题。这是正确的吗?如果是,我应该如何修改我的代码?
(我对使用sqlite3不太有经验...)
这是我的代码的实际开头:
import csv, bz2
names = ('ID', 'FORM')
filename = "huge-file.bz2"
with open(filename) as f:
f = bz2.BZ2File(f, 'rb')
reader = csv.DictReader(f, fieldnames=names, delimiter='\t')
tokens = [sentence for sentence in reader]
在此之后,我需要经历“标记”。如果我能处理这个庞大的bz2-文件,那就太好了-因此,非常感谢您的帮助!非常感谢您的协助!
最佳答案
该文件很大,读取所有文件将不起作用,因为您的进程将耗尽内存。
解决方案是读取文件中的块/行,并在读取下一个块之前对其进行处理。
清单理解线
tokens = [sentence for sentence in reader]
正在将整个文件读取到
tokens
,这可能导致进程内存不足。csv.DictReader
可以逐行读取CSV记录,这意味着在每次迭代中,会将1行数据加载到内存中。像这样:
with open(filename) as f:
f = bz2.BZ2File(f, 'rb')
reader = csv.DictReader(f, fieldnames=names, delimiter='\t')
for sentence in reader:
# do something with sentence (process/aggregate/store/etc.)
pass
请注意,如果在添加的循环中,将
sentence
中的数据存储在另一个变量(例如tokens
)中,则根据数据量的多少,可能仍会消耗大量内存。因此,最好将它们聚合,或为该数据使用其他类型的存储。更新资料
关于在流程中使用某些先前的行(如注释中所述),您可以执行以下操作:
然后,您可以将前一行存储在另一个变量中,该变量在每次迭代时都会被替换。
或者,如果您需要多行(后退),则可以得到最后一个
n
行的列表。怎么样
将collections.deque与
maxlen
一起使用以跟踪最后的n
行。从文件顶部的deque
标准模块导入collections
。from collections import deque
# rest of the code ...
last_sentences = deque(maxlen=5) # keep the previous lines as we need for processing new lines
for sentence in reader:
# process the sentence
last_sentences.append(sentence)
我建议使用上述解决方案,但您也可以使用列表自己实施,并手动跟踪其大小。
在循环之前定义一个空列表,在循环结束时检查列表的长度是否大于所需长度,从列表中删除较旧的项目,然后追加当前行。
last_sentences = [] # keep the previous lines as we need for processing new lines
for sentence in reader:
# process the sentence
if len(last_sentences) > 5: # make sure we won't keep all the previous sentences
last_sentences = last_sentences[-5:]
last_sentences.append(sentence)