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