进阶版:https://blog.csdn.net/youand_me/article/details/78890316
Python 中的 struct 模块
from struct import *
Python 提供了三个与 pack 和 unpack 相关的函数
1 2 3 |
|
第一个函数 pack 负责将不同的变量打包在一起,成为一个字节字符串。
第二个函数 unpack 将字节字符串解包成为变量。
第三个函数 calsize 计算按照格式 fmt 打包的结果有多少个字节。
pack 操作
Pack 操作必须接受一个 template string 以及需要进行 pack 一组数据,这就意味着 pack 处理操作 定长 的数据
1 2 3 4 5 6 |
|
上面的代码将两个整数 12 和 34,一个字符串 “abc” 和一个整数 56 一起打包成为一个字节字符流,然后再解包。其中打包格式中明确指出了打包的长度: "2I" 表明起始是两个 unsigned int , "3s" 表明长度为 4 的字符串,最后一个 "I" 表示最后紧跟一个 unsigned int ,所以上面的打印 b 输出结果是:(12, 34, ‘abc', 56),完整的 Python pack 操作支持的数据类型见下表。
如果想传入多个而且数量可变的参数,可以采用先将变量放入tuple中,再传给pack
args
=
(
"H"
,
"ello world "
,
5
)
struct.pack(
"c12si"
,
*
args)
# 等价于
struct.pack(
"c12si"
,
"H"
,
"ello world "
,
5
)
计算字节大小
可以利用 calcsize 来计算模式 “2I3sI” 占用的字节数
1 |
|
可以看到上面的三个整型加一个 3 字符的字符串一共占用了 16 个字节。为什么会是 16 个字节呢?不应该是 15 个字节吗?1 个 int 4 字节,3 个字符 3 字节。但是在 struct 的打包过程中,根据特定类型的要求,必须进行字节对齐(关于字节对齐详见 https://en.wikipedia.org/wiki/Data_structure_alignment) 。由于默认 unsigned int 型占用四个字节,因此要在字符串的位置进行4字节对齐,因此即使是 3 个字符的字符串也要占用 4 个字节。
再看一下不需要字节对齐的模式
1 |
|
由于单字符出现在两个整型之后,不需要进行字节对齐,所以输出结果是 9。
unpack 操作
对于 unpack 而言,只要 fmt 对应的字节数和字节字符串 string 的字节数一致,就可以成功的进行解析,否则 unpack 函数将抛出异常。例如我们也可以使用如下的 fmt 解析出 a :
1 2 3 |
|
不定长数据 pack
如果打包的数据长度未知该如何打包,这样的打包在网络传输中非常常见。处理这种不定长的内容的主要思路是把长度和内容一起打包,解包时首先解析内容的长度,然后再读取正文。
打包变长字符串
对于变长字符在处理的时候可以把字符的长度当成数据的内容一起打包。
1 2 |
|
上面代码把字符 s 的长度打包成内容,可以在进行内容读取的时候直接读取。
解包变长字符串
1 2 |
|
解包变长字符时首先解包内容的长度,在根据内容的长度解包数据
为了同c中的结构体交换数据,还要考虑有的c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.定义如下:
Character Byte order Size and alignment
@ native native 凑够4个字节
= native standard 按原字节数
< little-endian standard 按原字节数
> big-endian standard 按原字节数
! network (= big-endian)
standard 按原字节数
使用方法是放在fmt的第一个位置,就像’@5s6sif’