简介
python strtuct模块主要在Python中的值于C语言结构之间的转换。可用于处理存储在文件或网络连接(或其它来源)中的二进制数据。
主要函数
函数名 | 返回类型 | 描述 |
---|---|---|
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)占用多少字节的内存,注意对齐方式 |
其中最常用的函数为:pack()
和 unpack()
格式字符
fmt格式有以下定义:
Format | C Type | Python | 字节数 |
---|---|---|---|
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 | char[] | bytes | |
p | char[] | bytes | |
P | void * | integer |
1. c,s和p按照bytes对象执行转码操作,但是在使用UTF-8编码时,也支持str对象。
2. _Bool在C99中定义,如果没有这个类型,则将这个类型视为char,一个字节;
3. q和Q只适用于64位机器;
4. 每个格式前可以有一个数字,表示这个类型的个数,如s格式表示一定长度的字符串,4s表示长度为4的字符串;4i表示四个int;
5. P用来转换一个指针,其长度和计算机相关;
6. f和d的长度和计算机相关;
示例:
import struct
// ">I"的意思是:
// >表示字节顺序是大端(big-endian),也就是网络序,I表示4字节无符号整数。
// 后面的参数个数要和处理指令一致。
b = struct.pack('>I', 1024)
print(b)
// ">IH"的说明,后面的bytes依次变为I:4字节无符号整数 和 H:2字节无符号整数。
i = struct.unpack(">IH", b"\xf0\xf0\xf0\xf0\x80\x80")
print(i)
输出:
b'\x00\x00\x04\x00'
(4042322160, 32896)
对齐方式
为了同c中的结构体交换数据,还要考虑c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符(">"等)来改变对齐方式.定义如下:
Character | Byte order | Size | Alignment |
---|---|---|---|
@(默认) | 本机 | 本机 | 本机,凑够4字节 |
= | 本机 | 标准 | none,按原字节数 |
< | 小端 | 标准 | none,按原字节数 |
> | 大端 | 标准 | none,按原字节数 |
! | network(大端) | 标准 | none,按原字节数 |
如果不懂大小端,见大小端参考网址.
实例
1.通常的打包和解包
# 打包和解包
import struct
import binascii
values = (1, b'good', 1.22) # 查看格式化对照表可知,字符串必须为字节流类型。
s = struct.Struct('I4sf')
packed_data = s.pack(*values)
unpacked_data = s.unpack(packed_data)
print('Original values:', values)
print('Format string :', s.format)
print('Uses :', s.size, 'bytes')
print('Packed Value :', binascii.hexlify(packed_data)) # 字节流和ascii转换
print('Unpacked Type :', type(unpacked_data), ' Value:', unpacked_data)
输出:
b'\x01\x00\x00\x00good\xf6(\x9c?'
Original values: (1, b'good', 1.22)
Format string : I4sf
Uses : 12 bytes
Packed Value : b'01000000676f6f64f6289c3f'
Unpacked Type : <class 'tuple'> Value: (1, b'good', 1.2200000286102295)
2.使用buffer来进行打包和解包
使用通常的方式来打包和解包会造成内存的浪费,所以python提供了buffer的方式:
# 通过buffer方式打包和解包
import struct
import binascii
import ctypes
values = (1, b'good', 1.22) # 查看格式化字符串可知,字符串必须为字节流类型。
s = struct.Struct('I4sf')
buff = ctypes.create_string_buffer(s.size)
s.pack_into(buff, 0, *values)
unpacked_data = s.unpack_from(buff, 0)
print('Original values:', values)
print('Format string :', s.format)
print('buff :', buff)
print('Packed Value :', binascii.hexlify(buff))
print('Unpacked Type :', type(unpacked_data), ' Value:', unpacked_data)
输出:
Original values: (1, b'good', 1.22)
Format string : I4sf
buff : <ctypes.c_char_Array_12 object at 0x104c061e0>
Packed Value : b'01000000676f6f64f6289c3f'
Unpacked Type : <class 'tuple'> Value: (1, b'good', 1.2200000286102295)
针对buff对象进行打包和解包,避免了内存的浪费。这里使用到了函数ctypes.create_string_buffer(init_or_size,size = None)
创建可变字符缓冲区。
返回的对象是c_char的ctypes数组。init_or_size必须是一个整数,它指定数组的大小,或者用于初始化数组项的字节对象。
3.使用buffer方式来打包多个对象
values1 = (1, b'good', 1.22) # 查看格式化字符串可知,字符串必须为字节流类型。
values2 = (b'hello', True)
s1 = struct.Struct('I4sf')
s2 = struct.Struct('5s?')
buff = ctypes.create_string_buffer(s1.size + s2.size)
s1.pack_into(buff, 0, *values1)
s2.pack_into(buff, s1.size, *values2)
unpacked_data_s1 = s1.unpack_from(buff, 0)
unpacked_data_s2 = s2.unpack_from(buff, s1.size)
print('Original values1:', values1)
print('Original values2:', values2)
print('buff :', buff)
print('Packed Value :', binascii.hexlify(buff))
print('Unpacked Type :', type(unpacked_data_s1), ' Value:', unpacked_data_s1)
print('Unpacked Type :', type(unpacked_data_s2), ' Value:', unpacked_data_s2)
输出:
Original values1: (1, b'good', 1.22)
Original values2: (b'hello', True)
buff : <ctypes.c_char_Array_18 object at 0x10483a840>
Packed Value : b'01000000676f6f64f6289c3f68656c6c6f01'
Unpacked Type : <class 'tuple'> Value: (1, b'good', 1.2200000286102295)
Unpacked Type : <class 'tuple'> Value: (b'hello', True)