文件很大,读取所有文件将无法正常工作,因为您的进程将耗尽内存。
解决方法是分块/行读取文件,并在读取下一个块之前对其进行处理。
列表理解行
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)中,仍可能会消耗大量内存,具体取决于数据的大小。因此,最好将它们聚合起来,或者为这些数据使用其他类型的存储。
更新
关于在您的流程中使用前面的一些行(如 cmets 中所述),您可以执行以下操作:
然后您可以将前一行存储在另一个变量中,该变量在每次迭代时都会被替换。
或者,如果您需要多行(后退),那么您可以列出最后的 n 行。
如何
使用collections.deque 和maxlen 来跟踪最后的n 行。从文件顶部的collections 标准模块导入deque。
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)