python之struct 模块详解_import struct-程序员宅基地

技术标签: 算法  python  c++  java  Python学习笔记  字符串  

struct 模块

一、struct简单介绍

注意:本文中出现的四个名词同义:二进制流、二进制数组、字节流、字节数组

1.引入

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

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

>>> n = 10240099
>>> b1 = (n & 0xff000000) >> 24
>>> b2 = (n & 0xff0000) >> 16
>>> b3 = (n & 0xff00) >> 8
>>> b4 = n & 0xff
>>> bs = bytes([b1, b2, b3, b4])
>>> bs
b'\x00\x9c@c'

非常麻烦。并且有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体.

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

2.什么是struct模块?

  • structPython 的内置模块
  • 在使用 socket 通信的时候, 大多数据的传输都是以二进制流的形式的存在, 而 struct 模块就提供了一种机制, 该机制可以将某些特定的结构体类型打包成二进制流的字符串然后再网络传输,而接收端也应该可以通过某种机制进行解包还原出原始的结构体数据

二、struct的功能

struct模块的基本功能:

  • 按指定格式将python数据转换为字节流数据;
  • 将字节流数据转换为指定的python数据类型;
  • 处理二进制文件数据;
  • 处理C语言中的结构体。

三、struct模块的基本使用

1、struct 的使用

struct 模块可以将任意大小的数字转换成一个固定长度(可选择)的 bytes, 这个原理类似于 hash 算法, 不论内容多大, 最终的 hash 值长度不变, 不同的是 hash 算法是不可逆的, 而且传入的原材料可以是文本、字符串等许多数据类型, struct 可以反解出原来的数据

ps : struct 模块只能转换数字, 不能转换其他的数据类型

2、模块的常用方法

struct模块中最重要的三个函数是pack(), unpack(), calcsize()

函数 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)占用多少字节的内存,注意对齐方式

3、属性

format 格式化字符串。
size 结构体的大小。

4、字节顺序,大小和对齐(Byte Order, Size, and Alignment)

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

Character 字符 Byte order 字节顺序 Size大小 Alignment对齐方式
@ native 按原字节 native 按原字节 native 按原字节
= native 按原字节 standard 标准 none 无
< little-endian 小端 standard 标准 none 无
> big-endian 大端 standard 标准 none 无
! network (= big-endian) 网络(=大端) standard 标准 none 无

使用方法是放在format的第一个位置,就像@5s6sif

5、打包字节长度对照表

字符(Format) cType c语言类型 Python type 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(大写i) unsigned int integer 4
l(小写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 charl string
p charl string
P void* integer

注意:

  1. _Bool在C99中定义,如果没有这个类型,则将这个类型视为char,一个字节;
  2. q和Q只适用于64位机器;
  3. 每个格式前可以有一个数字,表示这个类型的个数,如s格式表示一定长度的字符串,4s表示长度为4的字符串;4i表示四个int;
  4. P用来转换一个指针,其长度和计算机相关;
  5. f和d的长度和计算机相关;

5、pack 和 unpack基本使用

5.1、pack的基本用法:
>>> import struct
>>> struct.pack('>I', 10240099)
b'\x00\x9c@c'

pack的第一个参数是处理指令,'>I'的意思是:

>表示字节顺序是big-endian,也就是网络序,I表示4字节无符号整数。

后面的参数个数要和处理指令一致。

  • 正确使用示例
import struct

res = struct.pack("i",1234566)  # 传入的必须是 int 类型
print(res)          # b'\x86\xd6\x12\x00'  (查看内容)
print(type(res))    # <class 'bytes'>      (查看类型)

res2 = struct.unpack("i",res)   # 使用什么 Format 打包就用什么解包
print(res2)         # (1234566,)           (是个元组)
print(type(res2))   # <class 'tuple'>      (查看类型)
print(res2[0])      # 1234566         
错误示例
  • 传入非int类型引发的错误示例
import struct
res=struct.pack("i","淘小欣")
'''
抛出异常:struct.error: required argument is not an integer(参数必须是整数)
'''
5.2、unpack基本使用
  • unpackbytes变成相应的数据类型:
>>> struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')
(4042322160, 32896)

根据>IH的说明,后面的bytes依次变为I:4字节无符号整数和H:2字节无符号整数。

所以,尽管Python不适合编写底层操作字节流的代码,但在对性能要求不高的地方,利用struct就方便多了。

  • 传入多个值示例:

    res = struct.pack("hiq",12,23,451312)  # 传入多个值, 并使用不同的 Fromat
    print(res)  # b'\x0c\x00\x00\x00\x17\x00\x00\x00\xf0\xe2\x06\x00\x00\x00\x00\x00'
    print(type(res))  # <class 'bytes'>
    
    a,b,c = struct.unpack("hiq",res)  # 使用解压赋值,有几个值就需要有几个 Fromat
    print(a,b,c)                      # 12 23 451312
    
    
  • 打包一个 json 后的信息长度, 在 socket 中可用于发送报头(报头为固定长度)

    import struct
    import json
    dic= {
          
        "header_name":"tes.txt",
        "total_size":3,
        "heash":"淘小欣"
    }
    res = json.dumps(dic)  # 将报头序列化
    lens = struct.pack("i",len(res))  # 将报头的长度传入并打包
    lens2 = struct.unpack("i",lens)   # 假设通信另一端收到打包的二进制,再进行解包拿到长度
    print(lens2)    # (74,)
    print(lens[0])  # 74
    
    
错误示例:
  • 解包时使用的 Format 不一致错误示例
import struct

res = struct.pack("i",123)

res2 = struct.unpack("q",res)
# struct.error: unpack requires a buffer of 8 bytes

  • Fromat 与值不一致错误示例

    with open("aaa.txt","wb")as f:
        for i in range(5):
            res = struct.pack("i",i)
            f.write(res)
            
    with open("aaa.txt","rb")as f:
        res = f.read()
        print(res)
        a,b,c,d,e= struct.unpack("i",res)  # 打包的时候是 5 个值, 解包的时候也要传 5 个值
        print(a,b,c,d,e)  # 抛出异常 : struct.error: unpack requires a buffer of 4 bytes
    
    

五、参考资料

  • 官方文档:https://docs.python.org/3/library/struct.html#format-characters
  • https://docs.python.org/zh-cn/2/library/struct.html
  • https://www.liaoxuefeng.com/wiki/1016959663602400/1017685387246080
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44621343/article/details/112793520

智能推荐

c#保留小数点后位数的方法-程序员宅基地

文章浏览阅读62次。Double dValue = 95.12345; int iValue = 10000; string strValue = "95.12345"; string result = ""; result = Convert.ToDouble(dValue).ToS..._c#中数据保留小数点后一位

2020计算机预推免(保研边缘人) | 重大、北邮、浙大软院、大连理工、华东师范、同济_大连理工软件学院预推免-程序员宅基地

文章浏览阅读1.8w次,点赞32次,收藏225次。2020计算机保研预推免|重大、北邮、浙大软院、大连理工、华东师范、同济预推免(按时间顺序)重庆大学北邮大连理工软件华东师范大学同济计算机其它所有大学申请通用:报名材料准备(Almost every school needs ):个人陈述/简历CV,获奖证明,中文成绩单,四六级成绩单面试准备(Almost every school asks):自我介绍(中英文/PPT自我陈述),英文问答,项目(竞赛/科研)的基本情况,专业知识、读研选择的研究方向相关问题保持手机通畅!!!时刻关注邮件_大连理工软件学院预推免

UIWebView取消长按放大(用于长按识别二维码)-程序员宅基地

文章浏览阅读74次。禁用长按UIWebView时放大镜及选择功能://通过js调用- (void)webViewDidFinishLoad:(UIWebView*)webView{ // Disable user selection [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement...._ios h5 长按识别二维码变成了放大

CCF题解20180302碰撞的小球_(1).初始时,三个小球的位置分别为4, 6, 8。 (2).一秒后,三个小球的位置分别为5, 7-程序员宅基地

文章浏览阅读801次,点赞3次,收藏3次。问题描述数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处。有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上,速度方向向右,速度大小为1单位长度每秒。  当小球到达线段的端点(左端点或右端点)的时候,会立即向相反的方向移动,速度大小仍然为原来大小。  当两个小球撞到一起的时候,两个小球会分别向与自己原来移动的方向相反的方向,以原来的速度大小继续移动。  现..._(1).初始时,三个小球的位置分别为4, 6, 8。 (2).一秒后,三个小球的位置分别为5, 7

工业互联网最全指导手册:工业互联网概念、七大关键技术技术、应用及案例梳理...-程序员宅基地

文章浏览阅读516次。省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库2022年7月份热门报告合集免费下载【高清在线】2022最高分国产电影:《隐入尘烟》为什么说产品能力是一个人的底层能力?饶毅:伟大复兴岂能依靠一群“太监”?!微信视频号实时推荐技术架构分享小红书推荐中台实践快手推荐系统精排模型实践今天给大家带来一份工业互联网干货资料《工业互联网基本概念及关键技术(含案例).pdf》..._中国移动通信集团常州分公司“纺纱5g工业互联网技术作业指导说明书”

ESP32-WROOM-32E,MQTT报错mqtt_message_receive:transport_read() error:errno=128_mqtt_message_receive: transport_read() error: errn-程序员宅基地

文章浏览阅读3.4k次,点赞3次,收藏4次。ESP32-WROOM-32E,MQTT使用采坑经验配置MQTT的是 esp_mqtt_client_config_t 结构体,里面包含了MQTT的信息,可根据具体场景配置。问题使用MQTT建立连接后,不收发数据,会有如下报错:_mqtt_message_receive: transport_read() error: errno=128

随便推点

mysql on update_MySQL自动设置create_time和update_time-程序员宅基地

文章浏览阅读3.7k次。参考表结构CREATE TABLE `t_baby` (`baby_id` int(11) NOT NULL AUTO_INCREMENT,`user_id` int(11) NOT NULL,`nickname` varchar(64) DEFAULT NULL,`avatar` varchar(64) DEFAULT ‘‘,`sex` int(2) unsigned NOT NULL DEFA..._mysql on update

c语言:1000瓶水,有一瓶是有毒的,现共有10只老鼠,怎么判断毒水?_1000杯水里找一个毒水-程序员宅基地

文章浏览阅读5.4k次。问题:1000瓶水,其中有一瓶是有毒的,一只老鼠喝下毒水会一天之后死亡,现在共有10只老鼠,怎么判断哪一瓶水是毒水?分析:2^10=1024,则可以考虑利用二进制求解解:给1000瓶水依次标号1至1000,将10只老鼠从右向左排成一列,第一瓶水让右边第1只老鼠喝,第2瓶水让第2只老鼠喝,第3瓶水让第1,2只老鼠喝,则第4瓶水让第3只老鼠喝,......第1000瓶水依次让第4,6,7,8,9,10_1000杯水里找一个毒水

03----3小时 用 websocket 实现聊天室 之项目静态页面搭建-程序员宅基地

文章浏览阅读797次,点赞9次,收藏20次。"往事随风"邀请你和"Boy"加入了群聊

USB升压型锂电充电芯片5v输入充8.4v锂电充电管理IC-程序员宅基地

文章浏览阅读255次,点赞5次,收藏4次。FS5080E 是一款支持双节串联锂离子电池的升压充电管理芯片,适应5V给两串锂电池8.4V充电,充电电流900MA,内部集成MOS功率管,具有完善的充电保护功能。未来,随着科技的不断进步和应用领域的不断拓展,该芯片将会迎来更加广阔的发展前景,为人们的生活带来更多便利和惊喜。1. 高效率:USB升压型锂电充电芯片采用先进的电路设计,能够实现高效的电压转换和充电管理,提高充电效率,缩短充电时间。4. 小型化:随着科技的发展,USB升压型锂电充电芯片的体积越来越小,方便集成到各种小型化、薄型化的电子产品中。

抽象泄漏定律_连接是一个泄漏的抽象-程序员宅基地

文章浏览阅读88次。抽象泄漏定律 作为初级Java开发人员,我们在职业生涯的早期就了解JDBC API。 我们知道它是非常重要的抽象,因为它允许以透明的方式更改基础数据库。 恐怕一个好主意是过度工程,因为: 我从未见过这样的数据库迁移发生超过十年了 大多数时候,写SQL 不是独立于数据库 尽管如此,无可否认,JDBC是Java中每个数据库交互的基础。 但是,我最近偶然发现了一个非常深藏在javax...._当水变成雾状(例如水滴的碰撞)时,就会分割出正负电荷。从水的表面分离出的水分子带负电荷(阴离子),而水滴整体带正电荷。这给予我们一个出乎意料的解释人在瀑布和喷泉边,甚至在雨后所感受到的清新的、使人振奋的感觉的原因。

Android 反射枚举Enum类型应用-程序员宅基地

文章浏览阅读1.1k次。网上关于反射枚举的案例似乎不多,也许是因为枚举在java里面枚举类型其实算个准类了,java编译的时候同样会生成一个enumname.Class文件,同时Enum是可以被子类直接继承的,所以有时候在反编译的时候反过跟头,掉过阴沟,真的坐船翻船,坐车爆胎,走路都要被石头绊倒的郁闷.同样也是证明不懂java基本知识,后果很严重!!!今天还是靠公司同事提醒了一下,发现枚举类型具有类的一些特性,虽然后_android 反射枚举

推荐文章

热门文章

相关标签