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 实战》书籍

相关推荐
MicrosoftReactor9 小时前
技术速递|如何使用 Playwright MCP 和 GitHub Copilot 调试 Web 应用
github·copilot·测试·playwright·mcp
艾莉丝努力练剑1 天前
【测试开发/测试】详解测试用例(下):详解设计测试用例的方法
linux·经验分享·测试用例·bug·测试
猫耳君1 天前
汽车网络安全 CyberSecurity ISO/SAE 21434 测试之三
安全·web安全·网络安全·汽车·测试·cyber·cybersecurity
艾莉丝努力练剑2 天前
【测试开发/测试】详解测试用例(上):测试用例、万能公式
运维·经验分享·测试开发·测试
蛋仔聊测试5 天前
pytest源码解析(三) 解析pytest 插件系统
python·测试
光殿9 天前
性能测试
测试
JenniferSmiling11 天前
Midscene初体验
测试
烧冻鸡翅QAQ12 天前
测试中的Bug
bug·测试
草莓熊Lotso13 天前
《从 0 建立测试开发认知:先搞懂 “是什么”,再学 “怎么做”》
经验分享·笔记·其他·测试