python之struct模块处理二进制

嵌入式开发中,有时需要对二进制流文件进行读写操作,一种方法是将二进制流文件转换为c语言数组形式。

这样可以使用python的struct模块,python的struct模块可以方便的进行字节与二进制之间的相互转换。

1 struct模块常用的几个函数

函数 说明
struct.pack(format, v1, v2, ...) 按照给定的格式(fmt),把数据封装成字符串流(包括2进制流)
struct.unpack(format, buffer) 按照给定的格式(fmt)解析字节流,返回解析出来的元组tuple
struct.unpack_from(format, buffer, offset=0) 该函数可以将缓冲区buffer中的内容在按照指定的格式fmt,从偏移量为offset=numb的位置开始进行读取,返回的是一个对应的元组tuple
struct.calcsize(format) 计算给定的格式(fmt)占用多少字节的内存

重要的是清楚格式(fmt)表达的含义,格式包含两个部分:

  1. 数据格式
  2. 数据字节序(大端or小端?)、对齐方式等。

数据格式如下:

Format C Type Python 字节数
x pad byte no value 1
c char string of length 1 1
b signed char integer 1
B unsigned char integer 1
? _Bool bool 1
h short integer 2
H unsigned short integer 2
i int integer 4
I unsigned int integer 4
l long integer 4
L unsigned long integer 4
q long long integer 8
Q unsigned long long integer 8
n ssize_t integer
N size_t integer
e float 2
f float float 4
d double float 8
s char[] string 1
p char[] string 1
P void * integer

字节序、对齐方式如下:

使用特殊字符来控制。

Character Byte order Size and alignment
@ native native 凑够4个字节,等于c语言中的sizeof
= native standard 按原字节数
< little-endian standard 按原字节数
> big-endian standard 按原字节数
! network (= big-endian) standard 按原字节数

细节可以查看官网,这里只展示一个例子。

3 将二进制数据转换成16进制数组

这里提供一个示例,来演示struct的使用。下面代码将二进制数据转换成16进制数组(代码参考2,有修改)。

# bin2hex.py
"""
将二进制数据的bin文件转换成C语言数组的形式并保存为 .c 源文件
"""
import sys, os
import struct

def bin2hex():
    if len(sys.argv) != 2:
        print("Usage: %s <bin_file>" % (sys.argv[0]))
        return

    filename = sys.argv[1]
    # 读取二进制文件存放到list列表中
    bindata = open(filename, 'rb').read()
    offset = 0
    fmt = '>B'
    binListData = []
    while offset < len(bindata):
        unpackdata = struct.unpack_from(fmt, bindata, offset)
        binListData.append("0x%.2x" % unpackdata[0])
        offset += struct.calcsize(fmt)

    ## 将列表中的数据写入到 .c 源文件中
    fileoutname = os.path.splitext(filename)[0] + '_arry.c'
    print("write to C array file %s" % fileoutname)
    with open(fileoutname, 'w') as fileOutput:
        fileOutput.write("unsigned long hexDataLength = {};\n".format(len(binListData)))
        fileOutput.write("unsigned char hexData[] = {\n")
        for i in range(len(binListData) - 1):
            if (i != 0) and (i % 16 == 0):
                fileOutput.write("\n")
            fileOutput.write(binListData[i] + ",")
        fileOutput.write(binListData[len(binListData) - 1] + "\n};")
    print("bin to C array success!")


if __name__ == '__main__':
    bin2hex()

脚本使用方法:

python3 bin2hex.py <binfile>

生成 binfile_arry.c 16进制数组

16进制数组转二进制bit流

此外,提供一个16进制数组转为二进制bit流的脚本:

# hexarray2bin
"""
将数组文件转换成二进制流bin文件
"""
import sys, os
import struct

def hexarray2bin():
    if len(sys.argv) != 2:
        print("Usage: %s <hex_array_file>" % (sys.argv[0]))
        return

    filename = sys.argv[1]
    # 读取数组存放到列表中
    data_tmp = []
    with open(filename, 'r') as fdata:
        lines = fdata.readlines()

    for line in lines:
        for i in line.strip().split(','):
            if i.isalnum():
                data_tmp.append(int(i, 16))

    ## 将列表中的数据写入到 .bin 二进制流中
    fileoutname = os.path.splitext(filename)[0] + '.bin'
    print("write to bin file %s" % fileoutname)

    fmt = ">%uI" % len(data_tmp)
    with open(fileoutname, 'wb') as fileOutput:
        bin_stream = struct.pack(fmt, *data_tmp)
        fileOutput.write(bin_stream)

    print("C array to bin success!")


if __name__ == '__main__':
    hexarray2bin()

数组文件如下(手动去头去尾):

0xfcff0000,0xfcff0000,0x00000000,0x00000000,0x0000fcff,0x00000000,0xfcff0000,0x0000f8ff,
0xf8fff8ff,0xf8fff8ff,0xfcfffcff,0xfcfffcff,0xfcfffcff,0xfcfffcff,0xfcfffcff,0xfcfffcff,
...

然后调用脚本:

python3 hexarray2bin <hexarrayfile>

生成 hexarrayfile.bin 二进制bit流数组

参考:

  1. Python使用struct处理二进制
  2. python将二进制数据的bin文件转换成16进制数组形式的C源文件
  3. struct — Interpret bytes as packed binary data — Python 3.11.3 documentation
posted @ 2023-06-01 12:11  sureZ_ok  阅读(396)  评论(0编辑  收藏  举报