【问题标题】:Converting python float to bytes将python浮点数转换为字节
【发布时间】:2019-11-12 07:14:26
【问题描述】:

我想将 Python 浮点数转换为字节数组,将其编码为 32 位 little-endian IEEE 浮点数,以便将其写入二进制文件。

在 Python 3 中现代 Pythonic 的实现方式是什么?对于整数,我可以使用my_int.to_bytes(4,'little'),但没有用于浮点数的to_bytes 方法。

如果我可以一次性为 numpy 数组中的每个浮点数执行此操作(使用 dtype numpy.float32),那就更好了。但请注意,我需要将其作为字节数组获取,而不是立即将数组写入文件。

有一些听起来相似的问题,但它们似乎主要是关于获取十六进制数字,而不是写入二进制文件。

【问题讨论】:

  • 处理单个原生 Python 标量的正确工具通常不是处理 NumPy 数组的正确工具。如果你想要一个 NumPy 解决方案,我建议专门询问 NumPy 并将常规 Python 类型排除在外(并期望从不了解 NumPy 的人那里得到非 NumPy 的答案)。
  • @user2357112 我会很高兴得到一个非 numpy 的答案,因为我一次写一个浮点数。我提到 numpy 主要是因为 numpy 解决方案不会受到伤害(无论如何我都在导入它)并且将来可能有用。
  • 您可能想尝试找到一种方法来避免一次写一个。那会很慢。
  • @user2357112 你是对的。幸运的是,numpy 解决方案使我能够做到这一点:)

标签: python numpy binary-data


【解决方案1】:

您可以使用structpackbytes 之类的,

>>> import struct
>>> struct.pack('<f', 3.14) # little-endian
b'\xc3\xf5H@'
>>> struct.pack('>f', 3.14) # big-endian
b'@H\xf5\xc3'

【讨论】:

    【解决方案2】:

    NumPy 数组带有一个 tobytes 方法,可以为您提供原始数据字节的转储:

    arr.tobytes()
    

    您可以指定 order 参数以对多维数组使用 C 顺序(行主要)或 F 顺序(列主要)。

    由于您想将字节转储到文件中,您可能还对tofile 方法感兴趣,它直接将字节转储到文件:

    arr.tofile(your_file)
    

    tofile 始终使用 C 顺序。

    如果需要改变字节顺序,可以使用byteswap 方法。 (newbyteorder 有更方便的签名,但不会改变底层字节,所以不会影响tobytes。)

    import sys
    if sys.byteorder=='big':
        arr = arr.byteswap()
    data_bytes = arr.tobytes()
    

    【讨论】:

    • 如何指定字节序?
    • @Nathaniel:答案已扩展。
    • 谢谢!从 hpaulj 的回答看来,我还可以在 dtype 中指定字节顺序,作为另一种方法
    • 如何从这个转储返回到numpy数组?
    【解决方案3】:

    使用正确的dtype,您可以将数组的数据缓冲区写入字节串或二进制文件:

    In [449]: x = np.arange(4., dtype='<f4')                                        
    In [450]: x                                                                     
    Out[450]: array([0., 1., 2., 3.], dtype=float32)
    In [451]: txt = x.tostring()                                                    
    In [452]: txt                                                                   
    Out[452]: b'\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00@\x00\x00@@'
    In [453]: x.tofile('test')                                                                                                                           
    In [455]: np.fromfile('test','<f4')                                             
    Out[455]: array([0., 1., 2., 3.], dtype=float32)
    In [459]: with open('test','br') as f: print(f.read())                          
    b'\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00@\x00\x00@@'
    

    改变结局:

    In [460]: x.astype('>f4').tostring()                                            
    Out[460]: b'\x00\x00\x00\x00?\x80\x00\x00@\x00\x00\x00@@\x00\x00'
    

    【讨论】:

    • 如何指定字节序?
    • 'f4'
    • 太好了,谢谢,这很好用。为了将来参考,tostringtobytes 的兼容性别名。
    【解决方案4】:

    numpy中有save/savez方法:

    将数据存储到磁盘,然后再次加载:

    >>> np.save('/tmp/123', np.array([[1, 2, 3], [4, 5, 6]]))
    >>> np.load('/tmp/123.npy')
    array([[1, 2, 3],
           [4, 5, 6]])
    

    将压缩数据存储到磁盘,然后再次加载:

    >>> a=np.array([[1, 2, 3], [4, 5, 6]])
    >>> b=np.array([1, 2])
    >>> np.savez('/tmp/123.npz', a=a, b=b)
    >>> data = np.load('/tmp/123.npz')
    >>> data['a']
    array([[1, 2, 3],
           [4, 5, 6]])
    >>> data['b']
    array([1, 2])
    >>> data.close()
    

    【讨论】:

    • savetofile 的不同之处在于它还将shapedtype 保存在初始数据块中。
    • @hpaulj shapedtype 不占用太多空间,但在完美读取和转换数据而不是得到一堆二进制垃圾方面发挥着至关重要的作用。
    • 作为一种完整的文件格式,.npy 绝对比原始字节转储提供更多信息和有用。作为较大文件的中间表示或组件,原始字节转储可能更有用。
    猜你喜欢
    • 2010-09-05
    • 1970-01-01
    • 2016-08-21
    • 2013-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多