【问题标题】:Handle huge bz2-file处理巨大的 bz2 文件
【发布时间】:2017-06-16 10:15:13
【问题描述】:

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

【问题讨论】:

    标签: python csv sqlite bzip2 linguistics


    【解决方案1】:

    文件很大,读取所有文件将无法正常工作,因为您的进程将耗尽内存。

    解决方法是分块/行读取文件,并在读取下一个块之前对其进行处理。

    列表理解行

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

    【讨论】:

    • 非常感谢您的建议!但是直接使用我们的“阅读器”(没有任何列表),不可能返回一个条目,是吗? (例如:之前,我可以这样做 "while tokens[i-1]['HEAD'] != dep: i = i-1 " 。这个解决方案仍然可能吗?(如何?)
    • * 我只需要后退一步来检查情况。
    • 然后您可以将前一行存储在另一个变量中,该变量在每次迭代时都会被替换。因此,总共 2 行将保留在内存中,1 行用于上一行,1 行用于当前行。或者,如果您需要多行(返回),那么您可以列出最后的 n 行。
    • 我更新了答案以演示如何跟踪最后几句话。
    • 非常感谢你,法扎德。你的建议和提示很有帮助!! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-13
    • 2017-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-02
    • 1970-01-01
    相关资源
    最近更新 更多