Python中的pack和unpack的使用
作者:三月沙 发布时间:2023-08-20 05:24:33
不同类型的语言支持不同的数据类型,比如 Go 有 int32、int64、uint32、uint64 等不同的数据类型,这些类型占用的字节大小不同,而同样的数据类型在其他语言中比如 Python 中,又是完全不同的处理方式,比如 Python 的 int 既可以是有符号的,也可以是无符号的,这样一来 Python 和 Go 在处理同样大小的数字时存储方式就有了差异。
除了语言之间的差别,不同的计算机硬件存储数据的方式也有很大的差异,有的 32 bit 是一个 word,有的 64 bit 是一个 word,而且他们存储数据的方式或多或少都有些差异。
当这些不同的语言以及不同的机器之间进行数据交换,比如通过 network 进行数据交换,他们需要对彼此发送和接受的字节流数据进行 pack 和 unpack 操作,以便数据可以正确的解析和存储。
计算机如何存储整型
可以把计算机的内存看做是一个很大的字节数组,一个字节包含 8 bit 信息可以表示 0-255 的无符号整型,以及 -128—127 的有符号整型。当存储一个大于 8 bit 的值到内存时,这个值常常会被切分成多个 8 bit 的 segment 存储在一个连续的内存空间,一个 segment 一个字节。有些处理器会把高位存储在内存这个字节数组的头部,把低位存储在尾部,这种处理方式叫 big-endian ,有些处理器则相反,低位存储在头部,高位存储在尾部,称之为 little-endian 。
假设一个寄存器想要存储 0x12345678 到内存中,big-endian 和 little-endian 分别存储到内存 1000 的地址表示如下
address | big-endian | little-endian |
---|---|---|
1000 | 0x12 | 0x78 |
1001 | 0x34 | 0x56 |
1002 | 0x56 | 0x34 |
1003 | 0x78 | 0x12 |
计算机如何存储 character
和存储 number 的方式类似,character 通过一定的编码格式进行编码比如 unicode,然后以字节的方式存储。
Python 中的 struct 模块
Python 提供了三个与 pack 和 unpack 相关的函数
struct.pack(fmt, v1, v2, ...)
struct.unpack(fmt, string)
struct.calcsize(fmt)
第一个函数 pack 负责将不同的变量打包在一起,成为一个字节字符串。
第二个函数 unpack 将字节字符串解包成为变量。
第三个函数 calsize 计算按照格式 fmt 打包的结果有多少个字节。
pack 操作
Pack 操作必须接受一个 template string 以及需要进行 pack 一组数据,这就意味着 pack 处理操作 定长 的数据
import struct
a = struct.pack("2I3sI", 12, 34, "abc", 56)
b = struct.unpack("2I3sI", a)
print b
上面的代码将两个整数 12 和 34,一个字符串 “abc” 和一个整数 56 一起打包成为一个字节字符流,然后再解包。其中打包格式中明确指出了打包的长度: "2I" 表明起始是两个 unsigned int , "3s" 表明长度为 4 的字符串,最后一个 "I" 表示最后紧跟一个 unsigned int ,所以上面的打印 b 输出结果是:(12, 34, ‘abc', 56),完整的 Python pack 操作支持的数据类型见下表。
Format | C Type | Python type | Standard size | Notes |
---|---|---|---|---|
x | pad byte | no value | ||
c | char | string of length 1 | 1 | |
b | signed char | integer | 1 | (3) |
B | unsigned char | integer | 1 | (3) |
? | _Bool | bool | 1 | (1) |
h | short | integer | 2 | (3) |
H | unsigned short | integer | 2 | (3) |
i | int | integer | 4 | (3) |
I | unsigned int | integer | 4 | (3) |
l | long | integer | 4 | (3) |
L | unsigned long | integer | 4 | (3) |
q | long long | integer | 8 | (2), (3) |
Q | unsigned long long | integer | 8 | (2), (3) |
f | float | float | 4 | (4) |
d | double | float | 8 | (4) |
s | char[] | string | ||
p | char[] | string | ||
P | void * | integer | (5), (3) |
计算字节大小
可以利用 calcsize 来计算模式 “2I3sI” 占用的字节数
print struct.calcsize("2I3sI") # 16
可以看到上面的三个整型加一个 3 字符的字符串一共占用了 16 个字节。为什么会是 16 个字节呢?不应该是 15 个字节吗?1 个 int 4 字节,3 个字符 3 字节。但是在 struct 的打包过程中,根据特定类型的要求,必须进行字节对齐(关于字节对齐详见 https://en.wikipedia.org/wiki/Data_structure_alignment) 。由于默认 unsigned int 型占用四个字节,因此要在字符串的位置进行4字节对齐,因此即使是 3 个字符的字符串也要占用 4 个字节。
再看一下不需要字节对齐的模式
print struct.calcsize("2Is") # 9
由于单字符出现在两个整型之后,不需要进行字节对齐,所以输出结果是 9。
unpack 操作
对于 unpack 而言,只要 fmt 对应的字节数和字节字符串 string 的字节数一致,就可以成功的进行解析,否则 unpack 函数将抛出异常。例如我们也可以使用如下的 fmt 解析出 a :
c = struct.unpack("2I2sI", a)
print struct.calcsize("2I2sI")
print c # 16 (12, 34, 'ab', 56)
不定长数据 pack
如果打包的数据长度未知该如何打包,这样的打包在网络传输中非常常见。处理这种不定长的内容的主要思路是把长度和内容一起打包,解包时首先解析内容的长度,然后再读取正文。
打包变长字符串
对于变长字符在处理的时候可以把字符的长度当成数据的内容一起打包。
s = bytes(s)
data = struct.pack("I%ds" % (len(s),), len(s), s)
上面代码把字符 s 的长度打包成内容,可以在进行内容读取的时候直接读取。
解包变长字符串
int_size = struct.calcsize("I")
(i,), data = struct.unpack("I", data[:int_size]), data[int_size:]
解包变长字符时首先解包内容的长度,在根据内容的长度解包数据
来源:http://sanyuesha.com/2018/03/10/why-pack-unpack/
猜你喜欢
- 数据库快照是怎样工作的可以使用典型的数据库命令CREATE DATABASE语句来生成一个数据库快照,在声明中有一个源数据库快照的附加说明。
- 本文在前面文章基础上介绍tkinter添加图片和文本,在这之前,我们需要安装一个图片库,叫Pillow,这个需要下载exe文件,根据下面图片
- 如何自动更新导航栏?下面看看如何具体使用Content Linking组件: <&nbs
- 利用MySQLfs这个工具,我么可以在MySQL关系数据库中存储文件系统。MySQLfs将文件系统中文件的字节内容分解成数据库中的元组,而数
- PHP sessionphp session 反序列化漏洞存在的原因:当序列化session和读取反序列化字符时采用的序列化选择器不一样时,
- golang中GOPATH的简单理解 1、为什么要配置GOPATH配置GOPATH的用意是为了方便项目的部署和构建,以及可以直接使用go g
- 方法一:<script language="JavaScript"> <!--
- 1、涉及到图的对比会用到子图形式展示先看看效果2、绘制代码如下accuracy_alexnet_clef = [78.05, 78.43,
- 本文是从百度百科中摘录出来的,asp在it中还有Application Service Provider,也就是应用服务供应商的意思。概述A
- CSS Sprites 简介:通常被意译为“CSS图像拼合”或“CSS贴图定位”。CSS Sprites并不是一门新技术,目前它已经在网页开
- 环境:pyecharts库,echarts-countries-pypkg,echarts-china-provinces-pypkg,ec
- 由于最近在处理shp文件,想要跳出arcpy的限制,所以打算学习一下pyshp包的使用方法。在使用《Python地理空间分析指南(第2版)》
- 开门见山自动化测试过程中,一般测试结果都会以邮件的形式发送给相关人员,那么,在Python中,如何编写代码将邮件发送给对应的用户?同时,发送
- 左右结构是平常页面中最经常看到的结构,简洁一些的页面就会使用边框将左右两边隔开,但往往由于左右两边的内容可能是不等高的,所以就会有一高一低的
- 回收站(Recycle Bin)从原理上来说就是一个数据字典表,放置用户删除(drop)掉的数据库对象信息。用户进行删除操作的对象并没有被数
- 为了画个图,被numpy这个模块的安装真的折腾疯了!!!一直装不上,花了几个小时,看了网上的很多教程、方法发现总结得不是很全,这里总结一下,
- 其实这里的静态页面并不是真正意义上的静态,但可以达到了静态页面的解析效率,还未经项目测试,拿来分享。代码如下:<% Cons
- 用analyze进行处理,定期进行处理ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tb1_name
- 用dicompyler软件打开dicom图像,头文件如图所示:当然也可以直接读取:ds = dicom.read_file('H:\
- 昨天ie8正式发布了,偶也去下载了一个,感觉很爽, 还在美的时候,突然发现很多网页都出问题,更可气的是自己的网站编辑器eWebEditor也