如何在Python 2.x中读写16位二进制数据?

8

我需要读写二进制数据,其中每个数据元素:

  • 大小 = 2字节(16位)
  • 编码 = 有符号2的补码
  • 字节序 = 大端或小端(必须可选)

是否可以不使用任何外部模块实现?如果可以,

  1. 如何使用read()从二进制文件中读取此类数据到整数数组L中?
  2. 如何使用write()将整数数组L写入二进制文件中?

3
你看过Python的struct模块吗? - Kai
2
我认为struct模块是开始的最佳地点。 - Exelian
1
@Sven Marnach:你有测量过吗? - S.Lott
@S.Lott:是的,去年回答这个问题时提到过。我不记得确切的数字了。 - Sven Marnach
@Sven Marnach: """逐个解包值"""?考虑使用struct.unpack(byteorder + str(len(rawbytes) // 2) + "h", rawbytes),其中byteorder为所需的<>。注意:我并不是在声称这比array方式更快,但我确实注意到array方式有时需要额外的byteswap步骤。 - John Machin
显示剩余2条评论
5个回答

12

我认为你最好使用 array 模块。它默认情况下以系统字节顺序存储数据,但是你可以使用 array.byteswap() 在不同字节顺序之间进行转换,并且你可以使用 sys.byteorder 查询系统的字节顺序。例子:

# Create an array of 16-bit signed integers
a = array.array("h", range(10))
# Write to file in big endian order
if sys.byteorder == "little":
    a.byteswap()
with open("data", "wb") as f:
    a.tofile(f)
# Read from file again
b = array.array("h")
with open("data", "rb") as f:
    b.fromfile(f, 10)
if sys.byteorder == "little":
    b.byteswap()

更一般地说,由于 OP 实际上想要一个 file_byteorder 参数,在输入和输出中都使用 if sys.byteorder!= file_byteorder:b.byteswap() - John Machin
@John:这就是我之前写上“例子”的原因 :) - Sven Marnach

2
from array import array
# Edit:
from sys import byteorder as system_endian # thanks, Sven!
# Sigh...
from os import stat

def read_file(filename, endian):
    count = stat(filename).st_size / 2
    with file(filename, 'rb') as f:
        result = array('h')
        result.fromfile(f, count)
        if endian != system_endian: result.byteswap()
        return result

array.fromfile() 总是需要两个参数。 - Sven Marnach
1
呃,那太不方便了。 :( - Karl Knechtel

1

我发现这对于从二进制文件中读取/写入数据到numpy数组非常有用:

import numpy as np

sys.argv[1] = endian # Pass endian as an argument to the program
if endian == 'big':
    precTypecode = '>'
elif endian == 'little':
    precTypecode = '<'

# Below: 'i' is for signed integer and '2' is for size of bytes. 
# Alternatively you can make this an if else statement to choose precision
precTypecode += 'i2'

im = np.fromfile(inputFilename, dtype = precTypecode) # im is now a numpy array
# Perform any operations you desire on 'im', for example switching byteorder
im.byteswap(True)
# Then write to binary file (note: there are some limitations, so refer doc)
im.tofile(outputFilename)

希望这有所帮助。

1

考虑使用

struct.unpack(byteorder + str(len(rawbytes) // 2) + "h", rawbytes)

其中,byteorder可以根据需要选择'<''>',打包方式也是类似的。注意:我并不声称这种方法比array更快,但我注意到array的方式有时需要额外的byteswap步骤。


1
“struct” 的方式总是需要额外的 “unpack()” 步骤。主要区别在于使用 “array.fromfile()” 时会得到一个数组,而使用 “struct” 方式则会得到一个 Python 列表。 - Sven Marnach

1
按要求,不使用任何外部模块:

with open("path/file.bin", "rb") as file:
    byte_content = file.read()
    list_16bits = [byte_content[i + 1] << 8 | byte_content[i] for i in range(0, len(byte_content), 2)]

在理解列表中,我们读取每两个字节。然后,通过按位操作连接这两个字节。这取决于大小端法,用于写入+1i的位置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接