Python 对字节流处理模块Struct 详解

背景:将物联网采集设备参数数据按照通信协议数据类型要求序列化成字节流推送到MQTT服务器。

Python 中有一个名为 Struct 的标准库,它可以执行 Python 值和以 Python 字节对象表示的 C 结构之间的转换。Python不适合编写底层操作字节流的代码,但在对性能要求不高的地方,利用struct就方便多了。

Python之Struct模块详解

1、struct模块作用

  1. 序列化:按照指定格式将Python数据转换为字节流字符串;【网络传输数据的基本形式是字节,也就是Byte。一个字节就是8个二进制位,8个Bit】

  2. 反序列化:按照指定格式将字节流转换为Python指定的数据类型;

  3. 用来处理存储在文件中或是从网络连接等其他来源获取的二进制数据:需要用'wb','rb'以二进制(字节流)写,读的方式来处理文件;

2、struct模块中的函数

函数 return explain
pack(fmt,v1,v2...) string 按照给定的格式(fmt),把数据转换成字符串(字节流),并将该字符串返回.
pack_into(fmt,buffer,offset,v1,v2...) None 按照给定的格式(fmt),将数据转换成字符串(字节流),并将字节流写入以offset开始的buffer中.(buffer为可写的缓冲区,可用array模块)
unpack(fmt,v1,v2.....) tuple 按照给定的格式(fmt)解析字节流,并返回解析结果
pack_from(fmt,buffer,offset) tuple 按照给定的格式(fmt)解析以offset开始的缓冲区,并返回解析结果
calcsize(fmt) size of fmt 计算给定的格式(fmt)占用多少字节的内存,注意对齐方式

备注:

当打包或者解包的时,需要按照特定的方式来打包或者解包.该方式就是格式化字符串,它指定了数据类型,除此之外,还有用于控制字节顺序、大小和对齐方式的特殊字符.

1)、fmt格式符

格式符 C 类型 PYTHON 类型 STANDARD SIZE
x pad byte no value
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
f float float 4
d double float 8
s char[] string
p char[] string
P void * integer

2)对齐方式

为了同c中的结构体交换数据,还要考虑c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.

Character Byte order Size Alignment
@(默认) 本机 本机 本机,凑够4字节
= 本机 标准 none,按原字节数
< 小端 标准 none,按原字节数
大端 标准 none,按原字节数
! network(大端) 标准 none,按原字节数

****Struct模块打包和解包示例

1、进制转换问题引入

python 复制代码
res = int(input("请输入一个数字"))
print("十进制数字是:",res)
print("转换为二进制数据为:",bin(res))
print("转换为十进制数据为",hex(res))

请输入一个数字5
十进制数字是:5
转换为二进制数据为: 0b101
转换为十进制数据为 0x5

Python没有专门处理字节的数据类型。但由于b'str'可以表示字节,所以,字节数组=二进制str。而在C语言中,我们可以很方便地用struct、union来处理字节,以及字节和int,float的转换。

在Python中,比方说要把一个32位无符号整数变成字节,也就是4个长度的bytes,你得配合位运算符这么写:

ini 复制代码
#32位无符号整数变成字节
R=[_ for _ in range(4)]
temp = 10240099
R[0] = int(temp / 256 / 256 / 256)
temp = temp % (256 * 256 * 256)
R[1] = int(temp / 256 / 256)
temp = temp % (256 * 256)
R[2] = int(temp / 256)
temp = temp % 256
R[3] = temp
print(bytes(R))

【b'\x00\xa5g\xc0'】

所以转换很麻烦。如果换成浮点数就无能为力了,只能转换为整型,如果是有符号的,还需要加条件判断,所以为了使得这一过程变得简洁,Python有专门处理数据类型转换的模块struct

2、struct.pack打包和struct.unpack解包

Python提供了一个struct模块来解决bytes和其他二进制数据类型的转换。

  • 按指定格式将 Python 数据转换为字节流数据,对应函数为struct.pack
  • 将字节流数据转换为指定的 Python 数据类型,对应函数为struct.unpack

固定长度的整型,包括有符号整型或无符号整型。【浮点型可转换为整型】

整型范围

Int8 - -128 : 127

Int16 - -32768 : 32767

Int32 - -2147483648 : 2147483647

Int64 - -9223372036854775808 : 9223372036854775807

无符号整型范围

UInt8 - 0 : 255

UInt16 - 0 : 65535

UInt32 - 0 : 4294967295

UInt64 - 0 : 18446744073709551615

示例: struct的pack函数把任意数据类型变成bytes及unpack函数把bytes还原其他数据:

ini 复制代码
import struct
#转字节码
def generate_bytes(arr):
    """
    生成字节数流
    :param arr:
    :return:
    uint8 = B
    int8 = b
    uint16 = H
    int16 = h
    uint32 = I
    int32 = i
    < 小端
    > 大端
    """
    fmt = ">BHibI"
    to_bytes  = struct.pack(fmt, *arr)
    print("字节数据",to_bytes)

    bytes_str = struct.unpack(fmt, to_bytes)

    print("还原数据",bytes_str)

    return to_bytes,bytes_str
if __name__ == '__main__':
    # 测试数据
    arr = [5, 6500, 2147483647, -10, 8900023]
    generate_bytes(arr)


输入数据 [5, 6500, 2147483647, -10, 8900023]
字节数据 b'\x05\x19d\x7f\xff\xff\xff\xf6\x00\x87\xcd\xb7'
还原数据 (5, 6500, 2147483647, -10, 8900023)

此处>表示字节顺序为 big-endian(大端)。

测试新人可以学习《测试人的 Python 工具书》书籍《性能测试 JMeter 实战》书籍

相关推荐
狂师13 小时前
想做测试工具却不会写代码?怎么办?
人工智能·程序员·测试
ClouGence1 天前
从 5 天到 2 小时:AI Agent 如何搭建高效、可复用的全自动化测试体系?
agent·测试
狂师2 天前
用AI做自动化测试,哪些是真不行,哪些是你不会用?
人工智能·面试·测试
世事如云有卷舒3 天前
GoogTest测试框架
c++·测试
狂师7 天前
AI 测试提效 | 别搞万能 Skill,推荐用 5 个 Agent Skill 串起 UI 自动化全流程
前端·人工智能·测试
ClouGence7 天前
AI Agent 能写测试、跑流程,为什么回归测试还不能完全交给 AI?
前端·测试
红尘伴蝶舞9 天前
Android 17 局域网调试与 ACCESS_LOCAL_NETWORK 权限隔离实践
kotlin·测试·设计
Apifox13 天前
Apifox 7 月更新|审计日志、密钥扫描防护、Postman/OpenAPI / Swagger 导入体验优化
前端·后端·测试