由于你不知道pickle的内部运作,你需要使用另一种存储方式。下面的脚本使用tobytes() 函数将数据逐行保存在原始文件中。
由于每行的长度是已知的,它在文件中的偏移量可以通过seek() 和read() 计算和访问。之后,使用frombuffer() 函数将其转换回数组。
然而,最大的免责声明是未保存数组的大小(这也可以添加,但需要更多复杂性),并且此方法可能不像腌制数组那样可移植。
正如@PadraicCunningham 在他的comment 中指出的那样,memmap 可能是另一种优雅的解决方案。
性能评论:阅读完 cmets 后,我做了一个简短的基准测试。在我的机器(16GB RAM,加密 SSD)上,我能够在 24 秒内进行 40000 次随机行读取(当然,使用 20000x40000 矩阵,而不是示例中的 10x10)。
from __future__ import print_function
import numpy
import random
def dumparray(a, path):
lines, _ = a.shape
with open(path, 'wb') as fd:
for i in range(lines):
fd.write(a[i,...].tobytes())
class RandomLineAccess(object):
def __init__(self, path, cols, dtype):
self.dtype = dtype
self.fd = open(path, 'rb')
self.line_length = cols*dtype.itemsize
def read_line(self, line):
offset = line*self.line_length
self.fd.seek(offset)
data = self.fd.read(self.line_length)
return numpy.frombuffer(data, self.dtype)
def close(self):
self.fd.close()
def main():
lines = 10
cols = 10
path = '/tmp/array'
a = numpy.zeros((lines, cols))
dtype = a.dtype
for i in range(lines):
# add some data to distinguish lines
numpy.ndarray.fill(a[i,...], i)
dumparray(a, path)
rla = RandomLineAccess(path, cols, dtype)
line_indices = list(range(lines))
for _ in range(20):
line_index = random.choice(line_indices)
print(line_index, rla.read_line(line_index))
if __name__ == '__main__':
main()