python之struct模块处理二进制

发布时间 2023-06-01 12:17:00作者: sureZ_ok

嵌入式开发中,有时需要对二进制流文件进行读写操作,一种方法是将二进制流文件转换为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进制数组

参考:

  1. Python使用struct处理二进制
  2. python将二进制数据的bin文件转换成16进制数组形式的C源文件
  3. struct — Interpret bytes as packed binary data — Python 3.11.3 documentation