Python中的pack和unpack的使⽤
不同类型的语⾔⽀持不同的数据类型,⽐如 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
10000x120x78
10010x340x56
10020x560x34
10030x780x12
计算机如何存储 character
和存储 number 的⽅式类似,character 通过⼀定的编码格式进⾏编码⽐如 unicode,然后以字节的⽅式存储。
Python 中的 struct 模块字符串长度 python
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)
Format C Type Python type Standard size Notes 计算字节⼤⼩
可以利⽤ calcsize 来计算模式 “2I3sI” 占⽤的字节数
print struct.calcsize("2I3sI") # 16
再看⼀下不需要字节对齐的模式
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:]
解包变长字符时⾸先解包内容的长度,在根据内容的长度解包数据
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论