从二进制文件读取/写入Python列表

时间:2017-04-12 20:59:41

标签: python arrays numpy binaryfiles

根据Python Cookbook,下面是如何将元组列表写入二进制文件:

from struct import Struct
def write_records(records, format, f):
    '''
    Write a sequence of tuples to a binary file of structures.
    '''
    record_struct = Struct(format)
    for r in records:
        f.write(record_struct.pack(*r))

# Example
if __name__ == '__main__':
    records = [ (1, 2.3, 4.5),
                (6, 7.8, 9.0),
                (12, 13.4, 56.7) ]
    with open('data.b', 'wb') as f:
        write_records(records, '<idd', f)

效果很好。 为了阅读(大量二进制数据),作者推荐了以下内容:

>>> import numpy as np
>>> f = open('data.b', 'rb')
>>> records = np.fromfile(f, dtype='<i,<d,<d')
>>> records
array([(1, 2.3, 4.5), (6, 7.8, 9.0), (12, 13.4, 56.7)],
dtype=[('f0', '<i4'), ('f1', '<f8'), ('f2', '<f8')])
>>> records[0]
(1, 2.3, 4.5)
>>> records[1]
(6, 7.8, 9.0)
>>>

这也很好,但是这个record不是一个普通的numpy数组。例如,type(record[0])将返回<type 'numpy.void'>。更糟糕的是,我无法使用X = record[:, 0]提取第一列。

有没有办法有效地将二进制文件中的列表(或任何其他类型)加载到普通的numpy数组中? Thx提前。

1 个答案:

答案 0 :(得分:1)

In [196]: rec = np.fromfile('data.b', dtype='<i,<d,<d')
In [198]: rec
Out[198]: 
array([( 1,   2.3,   4.5), ( 6,   7.8,   9. ), (12,  13.4,  56.7)], 
      dtype=[('f0', '<i4'), ('f1', '<f8'), ('f2', '<f8')])

这是一个1d结构化数组

In [199]: rec['f0']
Out[199]: array([ 1,  6, 12], dtype=int32)
In [200]: rec.shape
Out[200]: (3,)
In [201]: rec.dtype
Out[201]: dtype([('f0', '<i4'), ('f1', '<f8'), ('f2', '<f8')])

请注意,其tolist看起来与原始records相同:

In [202]: rec.tolist()
Out[202]: [(1, 2.3, 4.5), (6, 7.8, 9.0), (12, 13.4, 56.7)]
In [203]: records
Out[203]: [(1, 2.3, 4.5), (6, 7.8, 9.0), (12, 13.4, 56.7)]

您可以使用以下任一列表创建二维数组:

In [204]: arr2 = np.array(rec.tolist())
In [205]: arr2
Out[205]: 
array([[  1. ,   2.3,   4.5],
       [  6. ,   7.8,   9. ],
       [ 12. ,  13.4,  56.7]])
In [206]: arr2.shape
Out[206]: (3, 3)

还有其他方法可以将结构化数组转换为“常规”数组,但这是最简单和最一致的。

常规数组的tolist使用嵌套列表。结构化版本中的元组旨在传达差异:

In [207]: arr2.tolist()
Out[207]: [[1.0, 2.3, 4.5], [6.0, 7.8, 9.0], [12.0, 13.4, 56.7]]

在结构化数组中,第一个字段是整数。在常规数组中,第一列与其他列相同,float。

如果二进制文件包含所有浮点数,您可以将其加载为1d的浮点数并重新整形

In [208]: with open('data.f', 'wb') as f:
     ...:         write_records(records, 'ddd', f)
In [210]: rec2 = np.fromfile('data.f', dtype='<d')
In [211]: rec2
Out[211]: array([  1. ,   2.3,   4.5,   6. ,   7.8,   9. ,  12. ,  13.4,  56.7])

但是为了利用二进制文件中的任何记录结构,你也可以按记录加载,这意味着结构化数组:

In [213]: rec3 = np.fromfile('data.f', dtype='d,d,d')
In [214]: rec3
Out[214]: 
array([(  1.,   2.3,   4.5), (  6.,   7.8,   9. ), ( 12.,  13.4,  56.7)], 
      dtype=[('f0', '<f8'), ('f1', '<f8'), ('f2', '<f8')])