处理巨大的bz2文件

时间:2017-06-16 10:15:14

标签: python csv sqlite bzip2 linguistics

我应该使用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文件会很棒 - 所以,非常欢迎任何帮助!非常感谢您的任何建议!

1 个答案:

答案 0 :(得分:2)

文件很大,读取所有文件都不会有效,因为你的进程内存不足。

解决方案是以块/行读取文件,并在读取下一个块之前处理它们。

列表理解线

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.dequemaxlen来跟踪最后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)