简介

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)