Python数据结构与算法(10)---二进制数据结构Struct_李元静的博客-程序员秘密_结果体的数据结构与python对应

技术标签: struct  python  字节序  新星计划  一天一篇Python库  数据结构  Python  

二进制数据结构Struct

在C/C++语言中,struct被称为结构体。而在Python中,struct是一个专门的库,用于处理字节串与原生Python数据结构类型之间的转换。

本篇,将详细介绍二进制数据结构struct的使用方式。

函数与Struct类

struct库包含了一组处理结构值得模块级函数,以及一个Struct类。格式指示符将由字符串格式转换为一种编译表示,这与处理正则表达式得方式类似。

这个转换会耗费一些资源,所以创建一个Struct实例并再这个实例上调用方法时,只完成一次转换,往往会更高效。

打包

Struct支持使用格式指示符将数据打包为字符串,另外支持从字符串解包数据,格式指示符由表示数据类型的字符串和可选的数量及字节序指示符构成。

下面,我们来打包一个元组,将其转换为16进制字节序列,示例如下:

import struct
import binascii

values = (2, 'lyj'.encode('UTF-8'), 3.8)
s = struct.Struct('I 3s f')
packed_data = s.pack(*values)
print("原值:", values)
print("格式指示符:", s.format)
print("大小:", s.size, 'bytes')
print("打包值:", binascii.hexlify(packed_data))

运行之后,效果如下:

打包

这里的格式指示符为“I 3s f”。前面介绍array数组时,我们已经列出过一个表格。其中I标识一个整型或长整型,3s表示3个字节字符串(lyj),f表示浮点数。

解包

struct库使用unpack()可以从打包的表示数据中抽取数据,这里直接复制上面的打包值,进行测试。示例如下:

import struct
import binascii

packed_data = binascii.unhexlify(b'020000006c796a0033337340')
s = struct.Struct('I 3s f')
unpacked_data = s.unpack(packed_data)
print("解包值:", unpacked_data)

运行之后,效果如下:

解包

虽然使用unpack()解包基本会得到相同值,但浮点数的值有微小的差别。

字节序指示符

默认情况下,值会使用原生C库的字节序(endianness)来编码。Struct的字节序指示符如下表所示:

代码 含义
@ 原生顺序
= 原生标准
< 小端
> 大端
! 网络顺序

示例如下:

import struct
import binascii

values = (2, 'lyj'.encode('UTF-8'), 3.8)
endianness = [
    ('@', '原生顺序'),
    ('=', '原生标准'),
    ('<', '小端'),
    ('>', '大端'),
    ('!', '网络顺序'),
]
for code, name in endianness:
    s = struct.Struct(code + ' I 3s f')
    packed_data = s.pack(*values)
    print("格式化字符串:", s.format, ' for ', name)
    print("大小:", s.size, 'bytes')
    print("打包:", binascii.hexlify(packed_data))
    print("解包:", s.unpack(packed_data))

运行之后,效果如下:
字节序

如果想改变字节序来编码,如上面代码所示,只需要改变格式串中提供一个显式的字节序指令,就可以很容易地覆盖这个默认选择。

缓冲区

通常在强调性能的情况下或者向扩展模块传入或传出数据时才会处理二进制打包数据。

为了避免为每个打包结构分配一个新缓冲区所带来的开销,通常情况下,我们使用pack_into()和unpack_from()方法支持直接写入预分配的缓冲区。

示例如下:

import struct
import binascii
import ctypes
import array

values = (2, 'lyj'.encode('UTF-8'), 3.8)
s = struct.Struct('I 3s f')
print("原始值:", values)
b = ctypes.create_string_buffer(s.size)
print("打包之前(缓冲区的值):", binascii.hexlify(b.raw))
s.pack_into(b, 0, *values)
print("打包之后(缓冲区的值):", binascii.hexlify(b.raw))
print("解包:", s.unpack_from(b, 0))

a = array.array('b', b'\0' * s.size)
print("打包之前(缓冲区的值):", binascii.hexlify(a))
s.pack_into(a, 0, *values)
print('打包之后(缓冲区的值):', binascii.hexlify(a))
print("解包:", s.unpack_from(a, 0))

运行之后,效果如下:

缓冲区

这里通过两种方式,创建缓冲区。其中size属性用于指出缓冲区需要的大小。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/liyuanjinglyj/article/details/115861919

智能推荐

服务器怎么互传文件,服务器互传文件_Bonsen 本森的博客-程序员秘密

服务器互传文件 内容精选换一换华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。华为云帮助中心,为用户提供产品简介、价格说明、购买指南、用户指南、API参考、最佳实践、常见问题、视频帮助等技术文档,帮助您快速上手使用华为云服务。服务器互传文件 相关内容在本地主机和Windows云服务器上分别安装QQ....

skynet.call流程_gneveek的博客-程序员秘密

本来想自己写下这个流程的,但是看到网上有人已经写了,就直接转过来吧,修正了原文中的一处错误。原文:探索skynet(四):服务之间的通信原文内容在《探索skynet(三):消息队列》中已经提到,skynet中每个服务都有自己的地址和消息队列。有了这个基础,理解服务之间的消息通信,就比较简单了。 skynet.call以最常用到的skynet.call为例,它通过调用skynet.core.send

nyoj18 The Triangle_nyoj 18_PandaCXY的博客-程序员秘密

题目来源:http://acm.nyist.net/JudgeOnline/problem.php?pid=18The Triangle时间限制:1000 ms  |  内存限制:65535 KB难度:4描述73 88 1 02 7 4 44 5 2 6 5(Figure 1)Figure 1 shows a numb

曼哈顿距离和切比雪夫距离_不想悲伤到天明的博客-程序员秘密

转载 https://www.cnblogs.com/zwfymqz/p/8253530.html本文只讨论二维空间中的曼哈顿距离与切比雪夫距离曼哈顿距离定义设平面空间内存在两点,它们的坐标为(x1,y1) (x2,y2) .则  即两点横纵坐标差之和, 两点在南北方向上的距离加上在东西方向上的距离煮个栗子如图所示,图中A,B 两点的曼哈顿距离为AC+B...

【Linux学习笔记12】如何修改文件或者目录的权限(chmod指令)以及修改所有者和所属组(chown命令/chgrp命令)_RayCongLiang的博客-程序员秘密

之前总结ls命令的时候也有讲过权限,那么这次是把权限更加细化,分享给大家。 首先,我们再次执行ls -l 命令查看一下。 其实这个在我的学习笔记6有详细说明,在这里分析一下这9位权限位。 我们拿这个为例子: 我们从第二位开始拆分为三段 rwx r-x r-x r:可读 w:可改写 x:可执行 - :没有该权利 第一段(rwx)表示的是:文件...

JAVA初级内容集合_DBA日志小记的博客-程序员秘密

JAVA堆里放的是实例的值   栈里放的是命令 栈快:数据量少变量:用来引用一块内存区域或是一个值,用标示符来表示,可以通过操作变量来操作变量所对应的内存区域或值块的值。1:简述Java的基本历史     java起源于SUN公司的一个GREEN的项目,其原先目的是为家用消费电子产品     发送一个信息的分布式代码系统,通过发送信息控制电视机、冰箱等.2:简单写出Java

随便推点

点滴_weixin_34275734的博客-程序员秘密

为什么80%的码农都做不了架构师?&gt;&gt;&gt; ...

第一篇博客,用以规划我的编程人生_weixin_30415113的博客-程序员秘密

本人编程小白。第一次写技术博客,希望制定一个学习计划,让自己慢慢成长为一名优秀的程序猿。 学习方向是成为一名全栈工程师。 前端方面:会用bootstrap设计网页,会用jQuery完成动作。 后端方面:会用Django框架实现逻辑,还要学会MySQL。 不知道Node.js是不是更适合全栈。希望也能学会。 另外,还要学会自己架设Linux服...

类加载机制_滴哩哩哩滴哩哩哩哒哒的博客-程序员秘密

原文链接http://hammer.coding.me/2016/10/26/jvm-1/在开始正文之前,我们先看两张图。先看一下java程序的执行流程图再看一下jvm的大致物理结构图一.类加载机制概念 Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制。Cla...

运用SQL Server Profiler监视查看自己写的sql语句_Marzlam的博客-程序员秘密

什么是SQL Server Profiler?SQL Server Profiler的中文意思是SQL Server事件探查,一个Sql的监视工具,可以具体到每一行Sql语句,每一次操作,和每一次的连接。为什么要使用SQL Server Profiler?我们在项目处理过程中,处理数据的归根结底是对数据库的操作,那么能够看到最根本的sql语句对于我们逻辑也好,测试也好能够提供一个很直观...

创建守护进程的步骤与练习,每隔1s向time.log写入系统时间!_RTC_Kai的博客-程序员秘密

守护进程守护进程的概念Ssh、打印、ftp等均属于守护进程。进程类型为d。特点:始终在后台运行,独立于任何终端,周期性的执行某种任务或等待处理特定事件。会话和控制终端:linux以会话、进程组的方式管理进程,每个进程属于一个进程组,会话是一个或多个进程的集合。通常用户打开一个终端时,系统会创建一个会话,shell为会话的首进程,所有通过该终端运行的进程都属于这个会话,会话最多只能由一个控制...

selenium3+java 编写第一个自动化脚本._java自动化脚本教程_春风十里、的博客-程序员秘密

前面介绍了搭建环境和启动浏览器,这篇写一个比较简单地自动化脚本。当然例子还是百度啦。getCurrentUrl是获取当前页面url;getTitle是 获取当前网页标题;我们怎么知道打开页面的标题是正确的呢这时候需要写一个断言; Java中有一个方法叫assert 中文名称:断言assert 表达式的值是boolean型表达了真值,可以为 true(真)或false...

推荐文章

热门文章

相关标签