在追加模式下加载使用 numpy.save 保存的数组

Posted

技术标签:

【中文标题】在追加模式下加载使用 numpy.save 保存的数组【英文标题】:loading arrays saved using numpy.save in append mode 【发布时间】:2016-06-15 07:53:59 【问题描述】:

我在追加模式下使用 numpy.save() 保存数组:

f = open("try.npy", 'ab')
sp.save(f,[1, 2, 3, 4, 5])
sp.save(f,[6, 7, 8, 9, 10])
f.close()

然后我可以在 LIFO 模式下加载数据吗? 也就是说,如果我现在想加载 6-10 数组,是否需要加载两次(使用 b):

f = open("try.npy", 'r')
a = sp.load(f)
b = sp.load(f)
f.close()

或者我可以直接加载第二个附加的存档吗?

【问题讨论】:

当你尝试时会发生什么? 试试什么?当我只使用 sp.load 时,我得到了第一次保存。只有当再次使用加载时,我才能获得第二次保​​存。因此,如果我总是想要最后一块,我需要跟踪我做了多少次保存(而不是只加载最后一个,不管我做了多少附加) append中的文件不需要打开;仅当您写入先前已写入的文件时。 'wb' 会像这样保存 2 次。 【参考方案1】:

我有点惊讶这种顺序保存和加载的工作原理。我认为它没有记录在案(请纠正我)。但显然每个save 都是一个独立的单元,load 读取到该单元的末尾,而不是文件的末尾。

将每个load 视为readline。您不能只读取文件的最后一行;你必须阅读它之前的所有内容。

嗯 - 有一种读取最后一个的方法 - 使用 seek 将读取的文件移动到特定点。但要做到这一点,您必须确切知道所需块的开始位置。

np.savez 是将多个数组保存到一个文件,或者更确切地说是一个 zip 存档的预期方式。


save 保存两部分,一个包含dtypeshapestrides 等信息的标头,以及数组数据缓冲区的副本。 nbytes 属性给出了数据缓冲区的大小。至少数字和字符串 dtype 是这种情况。

save doc 有一个使用打开文件的示例 - 使用 seek(0) 倒回文件以供 load 使用。

np.lib.npyio.format 有更多关于保存格式的信息。看起来可以通过读取前几个字节来确定标头的长度。您可能可以使用模块中的函数来执行所有这些读取和计算。


如果我从示例中读取整个文件,我会得到:

In [696]: f.read()
Out[696]: 
b"\x93NUMPY\x01\x00F\x00
'descr': '<i4', 'fortran_order': False, 'shape': (5,), \n
 \x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00
\x93NUMPY\x01\x00F\x00
'descr': '<i4', 'fortran_order': False, 'shape': (5,), \n
 \x06\x00\x00\x00\x07\x00\x00\x00\x08\x00\x00\x00\t\x00\x00\x00\n\x00\x00\x00"

我添加了换行符以突出显示该文件的不同部分。请注意,每个save 都以\x93NUMPY 开头。

打开文件f,我可以读取标题(或第一个数组):

In [707]: np.lib.npyio.format.read_magic(f)
Out[707]: (1, 0)
In [708]: np.lib.npyio.format.read_array_header_1_0(f)
Out[708]: ((5,), False, dtype('int32'))

我可以通过以下方式加载数据:

In [722]: np.fromfile(f, dtype=np.int32, count=5)
Out[722]: array([1, 2, 3, 4, 5])

我是从np.lib.npyio.format.read_array功能码推导出来的。

现在文件位于:

In [724]: f.tell()
Out[724]: 100

这是下一个数组的头部:

In [725]: np.lib.npyio.format.read_magic(f)
Out[725]: (1, 0)
In [726]: np.lib.npyio.format.read_array_header_1_0(f)
Out[726]: ((5,), False, dtype('int32'))
In [727]: np.fromfile(f, dtype=np.int32, count=5)
Out[727]: array([ 6,  7,  8,  9, 10])

我们在 EOF。

并且知道int32有4个字节,我们可以计算出数据占用20个字节。所以我们可以通过读取头部来跳过一个数组,计算数据块的大小,然后seek 跳过它以到达下一个数组。对于工作不值得的小型阵列;但对于非常大的,它可能很有用。

【讨论】:

有趣的是,seek(100) 在这个例子中找到了最后一部分,seek(0)seek(200) 找到了第一个部分。也许mmap_mode 是前进的方向? mmap_mode 旨在读取一个数组的连贯块;我无法想象它可以跨 save 块工作。 seek(200) 的工作让我有点惊讶。在我的测试中,它将文件放在最后,因此如果我进一步尝试loadread,我会收到与EOF 相关的错误。

以上是关于在追加模式下加载使用 numpy.save 保存的数组的主要内容,如果未能解决你的问题,请参考以下文章

numpy 保存/加载损坏数组

Numpy数组的保存与加载

Python中数据的保存和读取

使用 numpy 保存列表时内存不足

Numpy中数据的常用的保存与读取

Python Numpy中数据的常用的保存与读取方法