嵌入式开发中,有时需要对二进制流文件进行读写操作,一种方法是将二进制流文件转换为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)表达的含义,格式包含两个部分:
- 数据格式
- 数据字节序(大端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进制数组
参考: