为什么要进行 pack 操作和 unpack 操作

不同类型的语言支持不同的数据类型,比如 Go 有 int32、int64、uint32、uint64 等不同的数据类型,这些类型占用的字节大小不同,而同样的数据类型在其他语言中比如 Python 中,又是完全不同的处理方式,比如 Python 的 int 既可以是有符号的,也可以是无符号的,这样一来 Python 和 Go 在处理同样大小的数字时存储方式就有了差异。

除了语言之间的差别,不同的计算机硬件存储数据的方式也有很大的差异,有的 32 bit 是一个 word,有的 64 bit 是一个 word,而且他们存储数据的方式或多或少都有些差异。

当这些不同的语言以及不同的机器之间进行数据交换,比如通过 network 进行数据交换,他们需要对彼此发送和接受的字节流数据进行 pack 和 unpack 操作,以便数据可以正确的解析和存储。

也就是说 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

Python 中字节在机器中存储的字节顺序用字母表示如下:

Character Byte order Size Alignment
@ native native native
= native standard none
< little-endian standard none
> big-endian standard none
! network (= big-endian) standard none

计算机如何存储 character

和存储 number 的方式类似,character 通过一定的编码格式进行编码比如 unicode,然后以字节的方式存储。

Python 中的 struct 模块

Python 提供了三个与 pack 和 unpack 相关的函数

1
2
3
struct.pack(fmt, v1, v2, ...)
struct.unpack(fmt, string)
struct.calcsize(fmt)

第一个函数 pack 负责将不同的变量打包在一起,成为一个字节字符串。

第二个函数 unpack 将字节字符串解包成为变量。

第三个函数 calsize 计算按照格式 fmt 打包的结果有多少个字节。

pack 操作

Pack 操作必须接受一个 template string 以及需要进行 pack 一组数据,这就意味着 pack 处理操作定长的数据

1
2
3
4
5
6
import structa = 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” 占用的字节数

1
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 个字节。

再看一下不需要字节对齐的模式

1
print struct.calcsize("2Is") # 9

由于单字符出现在两个整型之后,不需要进行字节对齐,所以输出结果是 9。

unpack 操作

对于 unpack 而言,只要 fmt 对应的字节数和字节字符串 string 的字节数一致,就可以成功的进行解析,否则 unpack 函数将抛出异常。例如我们也可以使用如下的 fmt 解析出 a

1
2
3
c = struct.unpack("2I2sI", a)
print struct.calcsize("2I2sI")
print c   # 16 (12, 34, 'ab', 56)

不定长数据 pack

如果打包的数据长度未知该如何打包,这样的打包在网络传输中非常常见。处理这种不定长的内容的主要思路是把长度和内容一起打包,解包时首先解析内容的长度,然后再读取正文。

打包变长字符串

对于变长字符在处理的时候可以把字符的长度当成数据的内容一起打包。

1
2
s = bytes(s)
data = struct.pack("I%ds" % (len(s),), len(s), s)

上面代码把字符 s 的长度打包成内容,可以在进行内容读取的时候直接读取。

解包变长字符串

1
2
int_size = struct.calcsize("I")
(i,), data = struct.unpack("I", data[:int_size]), data[int_size:]

解包变长字符时首先解包内容的长度,在根据内容的长度解包数据

参考资料

  • http://www.perlmonks.org/?node_id=224666
  • https://docs.python.org/2/library/struct.html
  • http://kaiyuan.me/2015/12/25/python-struct/

python struct pack unpack相关推荐

  1. python struct pack解析_python struct pack

    这个struct主要是用来处理C结构数据的,读入时先转换为Python的字符串类型,然后再转换为Python的结构化类型,比如元组(tuple)啥的~ 一般输入的渠道来源于文件或者网络的二进制流. 在 ...

  2. python struct pack string_struct (String) – Python 中文开发手册

    Python 中文开发手册 struct (String) - Python 中文开发手册 该模块执行Python值与C结构之间的转换,表示为Python字符串.这可用于处理存储在文件或网络连接中的二 ...

  3. python struct pack string_python struct pack fmt格式

    Python使用struct处理二进制 有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c ...

  4. python struct.pack()函数 (返回一个字节对象,其中包含根据格式字符串fmt打包的值v1,v2,...)

    def pack(fmt, *args): # known case of _struct.pack"""pack(fmt, v1, v2, ...) -> byt ...

  5. python struct pack一个数组_Python中struct.pack的一个疑问

    展开全部 的确很奇怪.我试验了10几分钟,你按下面的方法来做就可以正确.import struct zzz = ("{Type:2}").encode("utf-8&qu ...

  6. Python struct.pack(“!dHHHH%ds“%len(self.data),tt,0,self.tap_lenght,self.tap_type,0,_data)里的%ds是什么意思

    今天在看一段Python代码时,看到如下代码 if timestamp:tt = time.time()else:tt = 0.0 if not isinstance(self.data,str):_ ...

  7. python struct pack解析_Python struct 详解

    最近在学习python网络编程这一块,在写简单的socket通信代码时,遇到了struct这个模块的使用,当时不太清楚这到底有和作用,后来查阅了相关资料大概了解了,在这里做一下简单的总结. 了解c语言 ...

  8. Python - struct模块、partical模块

    #partical方法胡定函数第一个参数 #可以使用iter迭代,但是配合iter使用要指定两个参数  #struct.pack()/unpack()只打包/解包四个字节(编码ASCII,虽然是ASC ...

  9. python中pack函数,python中struct.pack()函數和struct.unpack()函數

    python中的struct主要是用來處理C結構數據的,讀入時先轉換為Python的字符串類型,然后再轉換為Python的結構化類型,比如元組(tuple)啥的~.一般輸入的渠道來源於文件或者網絡的二 ...

  10. python unpack_python中struct.pack()函数和struct.unpack()函数

    python中的struct主要是用来处理C结构数据的,读入时先转换为Python的字符串类型,然后再转换为Python的结构化类型,比如元组(tuple)啥的~.一般输入的渠道来源于文件或者网络的二 ...

最新文章

  1. WebDriver自动化测试工具(3)---PhantomJS的使用
  2. Change Fiori launchpad logo
  3. [html] link标签的属性media有哪些值?都有什么作用?
  4. 将win server 2003 AD域升级到win server 2012 R2
  5. C++数组动态分配空间国外玩家最关注的韩游
  6. 安卓安装包不能覆盖原安装包_LOL手游全网最简单注册,安装教程,安卓 IOS皆可登录!攻略群有游戏安装包!...
  7. 数据结构之查找的概念及简单实现
  8. Python电影推荐系统
  9. OpenGL第八版--初识OpenG
  10. matlab画gds图,Matlab GDS流程.doc
  11. 数学规划模型之线性规划
  12. 同时下载多个文件,同时展示多个文件的下载进度
  13. <Zhuuu_ZZ>大数据技术之Flume详解
  14. java 图片质量压缩_java图片高质量压缩
  15. Elasticsearch系列-搜索操作
  16. wow语音聊天服务器无法使用,无法正常使用《星际争霸II》语音聊天
  17. Python3.6 车牌识别代码源码
  18. Android 虚拟机与类加载机制
  19. 转载:Java 关于中文乱码问题的解决方案与经验
  20. ArcGIS二次开发基础教程(11):网络分析之最短路径分析

热门文章

  1. 阿尔法蛋机器人tf卡_入手评价科大讯飞阿尔法蛋S阿尔法蛋智能机器人功能优缺点评测...
  2. [JAVA]EXCEL工具推荐-MyExcel
  3. 微信小程序开发工具报错对应的服务器证书无效
  4. 客户消费积分管理系统的设计与实现
  5. 新年贺卡php,PS设计2016猴年大吉新年贺卡
  6. Wireshark实验 - TCP
  7. 传祺gac6480_传祺gs82020款,传祺GAC6480J2F5
  8. shell 执行qt生成文件_(原创)如何在QT下执行shell或外部程序(QT4)(shell)(mini6410)(smplayer)...
  9. android系统 备份恢复,Android系统备份及系统还原方法介绍
  10. python笔记3 闭包 装饰器 迭代器 生成器 内置函数 初识递归 列表推导式 字典推导式...