首页 > 解决方案 > 在 Python 3.6 中保存/加载大量字符串(列表/集)的最快方法是什么?

问题描述

该文件长 5GB。

我确实在 stackoverflow 上发现了一个类似的问题,人们建议使用 numpy 数组,但我认为这个解决方案适用于数字集合而不是字符串。

会有什么比 eval(list.txt) 或导入一个变量设置为列表的 python 文件吗?

加载/保存python字符串列表的最有效方法是什么?

标签: pythonpython-3.x

解决方案


对于只读情况:

import numpy as np

class IndexedBlob:
    def __init__(self, filename):
        index_filename = filename + '.index'
        blob = np.memmap(filename, mode='r')

        try:
            # if there is an existing index
            indices = np.memmap(index_filename, dtype='>i8', mode='r')
        except FileNotFoundError:
            # else, create it
            indices, = np.where(blob == ord('\n'))
            # force dtype to predictable file
            indices = np.array(indices, dtype='>i8')
            with open(index_filename, 'wb') as f:
                # add a virtual newline
                np.array(-1, dtype='>i8').tofile(f)
                indices.tofile(f)
            # then reopen it as a file to reduce memory
            # (and also pick up that -1 we added)
            indices = np.memmap(index_filename, dtype='>i8', mode='r')

        self.blob = blob
        self.indices = indices

    def __getitem__(self, line):
        assert line >= 0

        lo = self.indices[line] + 1
        hi = self.indices[line + 1]

        return self.blob[lo:hi].tobytes().decode()

一些附加说明:

  • 在末尾添加新字符串(只需以附加模式打开文件并写入一行 - 但要注意以前的损坏写入)很容易 - 但也要记住手动更新索引文件。mmap但请注意,如果您想查看现有IndexedBlob对象,则需要重新设置。您可以避免这种情况,只需保留“松散”对象的列表。
  • 按照设计,如果最后一行缺少换行符,则将其忽略(以检测截断或并发写入)
  • n您可以通过仅记录每个换行符,然后在查找时进行线性搜索来显着缩小索引的大小。然而,我发现这不值得。
  • 如果您对开始和结束使用单独的索引,则不再受限于按顺序存储字符串,这为突变开辟了多种可能性。但如果突变很少见,重写整个文件并重新生成索引并不太昂贵。
  • 考虑使用'\0'作为分隔符而不是'\n.

而且当然:

  • 无论您做什么,一般并发突变都很难。如果您需要做任何复杂的事情,请使用真正的数据库:这是当时最简单的解决方案。

推荐阅读