pyton struct模块

struct结构体在c语言中的作用,它定义了一种结构,里面包含不同类型的数据(int,char,bool等等),方便对某一结构对象进行处理。

在网络通信当中,大多传递的数据是以二进制流(binarydata)存在的。

当传递字节串时,不必担心太多的问题; 传递字符串之前也要使用string.encode(‘utf8’)转为字节串
而当传递诸如int、char之类的基本数据的时候,就需要有一种机制将某些特定的结构体类型打包成二进制流的字节串然后再网络传输,而接收端也应该可以通过某种机制进行解包还原出原始的结构体数据。

python中的struct模块就提供了这样的机制,该模块的主要作用就是对python基本类型值与用python字节串格式表示的C struct类型间的转化(This module performs conversions between Python values and C structs represented as Python bytes objects.)

1. 基本的pack和unpack

原型:struct.pack(format, v1, v2, …)
struct.unpack(format, buffer)

使用pack和unpack分别对数据进行打包和解包:

import structp_data = struct.pack('i', 25)
print(p_data)
print(struct.unpack('i', p_data))p1_data = struct.pack('B', 2)
print(p1_data)
print(struct.unpack('B', p1_data))
print(struct.calcsize('B'))  # 长度为一个字节# output
'''
b'\x19\x00\x00\x00'
(25,)
b'\x02'
(2,)
1
'''

struct.pack.format为"i"时,只能打包长度为10的数字,超过10位会抛出异常:

p_data = struct.pack('i', 1234567890)
print(p_data)
print(struct.unpack('i', p_data))
struct.calcsize('i') # 一个'i'转换后的长度为4,2个'i'则为8# output
'''
b'\xd2\x02\x96I'
(1234567890,)
'''

转换多个数据:

data = struct.pack('hhl', 1, 2, 3)
print(data) # 'hhl'分别是1,2,3的转换格式
print(struct.unpack('hhl', data))
struct.calcsize('hhl') # 以'hhl'格式转换得到的字节串长度# output
'''
b'\x01\x00\x02\x00\x03\x00\x00\x00'
(1, 2, 3)
'''

2. format和字节顺序参考表

  • format格式字符前面可以有整数num, 代表有num个需要转换的值,但’s’是例外
print(struct.pack('3c', b'a', b'b', b'c'))  # '3c'代表有3个要转换的字符
print(struct.pack('3s', b'abc')) # 对于's'格式,之前的数字被解释为bytes的长度

字节顺序的大端模式和小端模式

print(struct.pack('>i', 0x12345678)) # 大端模式, 地址从低到高,数据位从高到低
print(struct.pack('<i', 0x12345678)) # 小端模式

3. 使用struct的原因

将int转为bytes方法的速度比较:

import timeit
print(timeit.timeit('bytes([255])', number=1000000))
print(timeit.timeit('struct.pack("B", 255)', setup='import struct', number=1000000))
print(timeit.timeit('(255).to_bytes(1, byteorder="little")', number=1000000))

output

0.1463956000006874
0.08819799999764655
0.1185951000006753

结论: struct.pack() 函数执行整型到字节的转换可获得最佳执行性能

4. 利用buffer,使用pack_into和unpack_from方法

使用二进制打包数据的场景大部分都是对性能要求比较高的使用环境。
而在上面提到的pack方法都是对输入数据进行操作后重新创建了一个内存空间用于返回,也就是说我们每次pack都会在内存中分配出相应的内存资源,这有时是一种很大的性能浪费。

struct模块还提供了pack_into() 和 unpack_from()的方法用来解决这样的问题,也就是对一个已经提前分配好的buffer进行字节的填充,而不会每次都产生一个新对象对字节进行存储。

data = (b'ccc', 25, 38)
buf = bytearray(struct.calcsize('3s2i'))  # 预先创建一个缓冲区buf
struct.pack_into('3s2i', buf, 0, *data)  # 将打包的字节填充到缓冲区,从下标为0的位置开始
struct.unpack_from('3s2i', buf, 0)  # 从缓冲区buf下标为0的位置读取数据,并按格式'3s2i'解包

相比使用pack方法打包,pack_into 方法一直是在对buffer对象进行操作,而不会像pack那样要每次创建内存用于缓存字节串。

使用pack_into的offset参数,可以将多个python对象pack到一个缓冲区对象中,并可利用offset进行unpack:

data = (b'ccc', 25, 38)
data_format = '3s2i'data2 = (b'cze', 10)
data2_format = '3si'
buf = bytearray(struct.calcsize(data_format) + struct.calcsize(data2_format))
struct.pack_into(data_format, buf, 0, *data)
struct.pack_into(data2_format, buf, struct.calcsize(data_format), *data2)print(struct.unpack_from(data_format, buf, 0))
print(struct.unpack_from(data2_format, buf, struct.calcsize(data_format)))# output
'''
(b'ccc', 25, 38)
(b'cze', 10)
'''

5. 使用struct.Struct类简化操作

上面使用原始的函数将多个python对象pack到一个缓冲区队中的代码有些啰嗦,使用struct.Struct类创建一个Struct对象并调用其方法比使用相同格式的struct函数更有效,因为格式字符串只需要编译一次

import structdata = (b'ccc', 25, 38)
data2 = (b'cze', 10)s1_obj = struct.Struct('3s2i')
s2_obj = struct.Struct('3si')buf = bytearray(s1_obj.size + s2_obj.size)s1_obj.pack_into(buf, 0, *data)
s2_obj.pack_into(buf, s1_obj.size, *data2)print(s1_obj.unpack_from(buf, 0))
print(s2_obj.unpack_from(buf, s1_obj.size))# output
'''
(b'ccc', 25, 38)
(b'cze', 10)
'''

参考

浅析Python中的struct模块

struct模块使用相关推荐

  1. python3 struct模块 处理二进制 pack unpack用法

    python有时需要处理二进制数据,例如 存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用struct来处理c语言中的结构体. struct模块中最重要的三个 ...

  2. python 网络编程--socket模块/struct模块

    socket模块: 客户端:CS架构,  client -> server 浏览器:BS架构,  browser -> server 网络通信本质:传输字节 doc命令查看ip地址:ipc ...

  3. 解决socket粘包的两种low版模式 os.popen()和struct模块

    无注释版 os.popen()模式 server端 import socket import osphone = socket.socket() phone.bind(("localhost ...

  4. python struct模块的使用

    struct模块中的函数 函数 return explain pack(fmt,v1,v2-) string 按照给定的格式(fmt),把数据转换成字符串(字节流),并将该字符串返回. pack_in ...

  5. Python基础教程— Struct模块

    struct模块提供了用于在字节字符串和Python原生数据类型之间转换函数,比如数字和字符串. 该模块作用是完成Python数值和C语言结构体的Python字符串形式间的转换. 这可以用于处理存储在 ...

  6. python序列化模块struct_python的struct模块

    Python中缺少类似C语言structs这样直接对字节序列进行序列化和反序列化的语法,作为一门脚本语言这是不必要的,但作为一门完整的编程语言必须提供这样的能力,否则不能独立的处理二进制文件和数据流. ...

  7. python struct模块_python struct 模块

    struct模块用于二进制和结构体之间的互相转化,此模块中大部分函数接受一个实现了Buffer协议的对象,最常见的实现了Buffer协议的对象包括bytes.bytearray等,大多数像byte数组 ...

  8. 模拟ssh, hashlib模块, struct模块, subprocess模块

    一. 模拟ssh # ===================================== 服务器端 =====================================import so ...

  9. python学习day32 黏包 struct模块

    为什么会出现黏包问题?  首先只有在TCP协议中才会出现黏包现象 是因为TCP协议是面向流的协议 在发送的数据 传输过程中 有缓存机制 来避免数据丢失 因此 在连续发送小数据的时候 以及接收大小不符的 ...

  10. python 二进制流_Python中对字节流/二进制流的操作:struct模块简易使用教程

    前言 前段时间使用Python解析IDX文件格式的MNIST数据集,需要对二进制文件进行读取操作,其中我使用的是struct模块.查了网上挺多教程都写的挺好的,不过对新手不是很友好,所以我重新整理了一 ...

最新文章

  1. Linux内核中的进程等待与其实现解析
  2. A folder failed to be moved——Android SDK的安装问题解决方案
  3. leetcode 746. 使用最小花费爬楼梯(dp)
  4. android面试题精选
  5. asp多表查询并显示_高级子查询
  6. c# —— 枚举和值的隐藏副作用
  7. ubuntu 16.04 重装失败:进入grub出不来
  8. RDS binglog
  9. 请问android如何录制acc格式音频
  10. 卡尔曼滤波算法推导及MATLAB实现
  11. 在windows 2003 中,启动SQL Server 2000 提示“没有找到MSVCR71.dll因此这个应用程序未能启动”
  12. 吃货在东京 -- 记那段吃不饱的日子 之四 台场的日本拉面
  13. 2018年1月西邻雪山自驾游攻略
  14. css 属性 position:sticky (粘滞的) 制作导航吸顶效果
  15. 使用python切割图片
  16. Android之仿微信发朋友圈图片选择功能
  17. 966. 元音拼写检查器
  18. python怎么把字体变大_Pycharm 字体大小调整设置的方法实现
  19. Latex——连乘符号
  20. STM32外部中断干扰解决方案

热门文章

  1. Filament 渲染引擎剖析 之 FrameGraph 1 虚拟资源的定义与创建
  2. 面试 -- 操作系统与计算机网络
  3. 关于数据库的操作语句
  4. linux安装mysql图解,linux中怎么安装mysql5.6.12版本图解
  5. 测试显卡位宽软件,科普:显卡位宽基础知识指南
  6. 举个栗子!Tableau 技巧(189):用拱形图 ARC chart 呈现数据分布
  7. 基于Snort的入侵检测系统_相关论文
  8. 直线检测——Radon变换/霍夫变换/基于快速傅里叶变换的直线检测
  9. 【数据库课程】研讨02
  10. quectel模块增加发送功率流程