1.1.用途    
        执行Python值和表示为bytes对象C结构之间转换,将Python基本类型转换成byte.    
        用于处理文件或网络中的二进制数据以及其他来源;
        
1.2.说明: 
        python中b'str'表示字节,字节数组=二进制str    
        C语言用struct、union处理字节,以及字节和int,float的转换    
   
1.3.注意:    
        处理与平台无关数据格式或省略隐式填充字节,用standard大小和对齐,不是native
2.1.struct函数    
 
缓冲区参数:    
    缓冲区是指实现缓冲区协议并提供可读写缓冲区对象。
    常见bytes和bytearray支持缓冲区协议的对象可被读取 / 填充无需额外的复制bytes对象 

函数:
    struct.pack(fmt, v1, v2, ...)
        用途:根据指定格式 fmt 将值 v1, v2打包成字节对象

    struct.pack_into(fmt, buf, offset, v1, v2, ...)  
        用途:按偏移量 offset 根据指定格式 fmt 将值 v1, v2打包成字节对象并写入缓冲区    
        说明:请注意,偏移量是必需的参数
       
    struct.unpack(fmt, buf)
        用途:根据格式 fmt 从缓冲区解压数据,以 tuple 的形式返回
        参数:缓冲区大小(字节)必须与格式所需大小相匹配,如 calcsize() 所示

    struct.unpack_from(fmt, buf, offset=0)
        用途:根据格式字符串格式从位置偏移处开始从缓冲区解包
        返回:元组
        说明:缓冲区大小(字节,减去偏移量)必须至少为格式所需大小如 calcsize() 所示

    struct.iter_unpack(fmt, buf)
        用途:根据格式字符串格式从缓冲区缓冲区迭代解压缩
        返回:迭代器,它将从缓冲区读取大小相同的块,直到其所有内容都被消耗掉。
        说明:缓冲区大小(字节)必须是格式所需大小倍数,如 calcsize()所示
                    每次迭代都会产生格式字符串指定的元组
                
    struct.calcsize(fmt)
        用途:计算格式字符串所对应的结果的长度
        返回:与格式字符串格式对应的struct 大小(以及由此生成字节对象的大小)pack(fmt, ...)
2.2.struct模块类:    
    
class struct.Struct(format)    
    用途:返回一个新Struct对象,它根据格式字符串格式写入和读取二进制数据
    说明:创建Struct对象并调用方法比调用struct函数更有效率,因为格式字符串只需编译一次   
    编译结构对象支持以下方法和

属性:    
    format 用于构造此Struct对象格式字符串    
    size   计算结构体大小(及由pack()生成字节对象大小)对应于format 
 
方法:       
    pack(v1,v2,... )    
        用途:同pack()函数使用编译后的格式。(len(result)将等于size)    
       
    pack_into(buffer,offset,v1,v2,... )    
        用途:同pack_into()函数使用编译后的格式    
       
    unpack(缓冲区)    
        用途:同unpack()函数使用编译后的格式。缓冲区大小以字节为单位必须相等size    
       
    unpack_from(buffer,offset = 0 )    
        用途:同unpack_from()函数同使用编译后格式。缓冲区大小(字节,减去偏移量)    
                    必须至少为 size    
       
    iter_unpack(缓冲区)   
        用途:同iter_unpack()函数使用编译后格式。缓冲区大小以字节为单位size

 

3.实例:

# python数据类型直接转换为byte:      
实例1.1:字符串 
   
# 编码仅能用于str, 其他5中基本类型不能应用    
a1 = 'str'    
b1 = a1.encode('utf-8')  # b'str'    
s1 = b1.decode('utf-8')  # 'str'    
    
实例1.2:数字    
# float不能转换    
n = 10240099    
b1 = (n & 0xff000000) >> 24    
b2 = (n & 0xff0000) >> 16    
b3 = (n & 0xff00) >> 8    
b4 = n & 0xff 
   
bs = bytes([b1, b2, b3, b4])# b'\x00\x9c@c'非常麻烦
实例2:打包解包示例 

实例2.1:
from struct import *    
 
# 参数'>I':字节顺序是big-endian网络序,I表示4字节无符号整数 
pack('>I', 10240099)  # b'\x00\x9c@c'       
            
# 参数个数要和处理指令一致    
pack('hhl', 1, 2, 3)  # b'\x00\x01\x00\x02\x00\x00\x00\x03'    
unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')  # (1, 2, 3)    
calcsize('hhl')                                                                # 8    

# 后面的bytes依次变为I:4字节无符号整数和H:2字节无符号整数            
unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')  # (4042322160, 32896)       
            
a = 20;b = 400 
# 整数转换为字符串(字节流)    
s = pack('ii', a, b)# :b'\x14\x00\x00\x00\x90\x01\x00\x00' <class 'bytes'>    
print('length: ', len(s))  # 输出:length:  8字节(int类型占用4个字节) 
   
s2 = unpack('ii', s)      # 格式符"i"表示转换为int,'ii'表示有两个int变量 
print(s2)                       # 输出:(20, 400)    
   
实例2.2:
import sys    
from struct import *    
from ctypes import create_string_buffer    
        
buf = create_string_buffer(12)    
print(repr(buf.raw))    
    # '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'    
        
pack_into("iii", buf, 0, 1, 2, -1)    
print(repr(buf.raw))    
    # b'\x01\x00\x00\x00\x02\x00\x00\x00\xff\xff\xff\xff'    
        
print(unpack_from("iii", buf, 0))  # (1, 2, -1)
实例2.3:
#解包字段可通过将它们分配给变量或通过将结果包装到指定元组中来命名:    
        
record = b'raymond   \x32\x12\x08\x01\x08'    
print(record)               #b'raymond   2\x12\x08\x01\x08'    
name, serialnum, school, gradelevel = unpack('<10sHHb', record)    
            
print('a1=%s;a2=%s;a3=%s;a4=%s'%(name, serialnum, school, gradelevel))# a1=b'raymond   ';a2=4658;a3=264;a4=8    

from collections import namedtuple    
Student = namedtuple('Student', 'name serialnum school gradelevel')    
print(Student) #<class '__main__.Student'>    
a=Student._make(unpack('<10sHHb', record))    
print(a)            # Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)    
            
'''    
namedtuple._make  返回命名元组的新实例,用新值替换指定字段    
Point = namedtuple('Point', ['x', 'y'])    
t = [11, 22]    
Point._make(t)#Point(x=11, y=22)    
'''    

#以下格式'llh0l'在末尾指定两个填充字节,假定长度在4个字节边界上对齐:    
a=pack('llh0l', 1, 2, 3)    
print(a)     #b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00'    

实例2.4:
string = b'test astring'    
format = '5s 4x 3s'    
print(struct.unpack(format, string))  # (b'test ', b'ing')    
            
string = b'he is not very happy'    
format = b'2s 1x 2s 5x 4s 1x 5s'    
print(struct.unpack(format, string))  # (b'he', b'is', b'very', b'happy')
实例2.5:Windows的位图文件(.bmp)    
#BMP格式采用小端方式存储数据,文件头结构按顺序如下:    
'''   
两个字节:'BM'表示Windows位图,'BA'表示OS/2位图;    
一个4字节整数:表示位图大小;    
一个4字节整数:保留位,始终为0;    
一个4字节整数:实际图像的偏移量;    
一个4字节整数:Header的字节数;    
一个4字节整数:图像宽度;    
一个4字节整数:图像高度;    
一个2字节整数:始终为1;    
一个2字节整数:颜色数。 
'''   

#读入bmp文件前30个字节:    
s =b'\x42\x4d\x38\x8c\x0a\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00    
\x00\x00\x80\x02\x00\x00\x68\x01\x00\x00\x01\x00\x18\x00'    
            
#用unpack读取:    
import struct    
a=struct.unpack('<ccIIIIIIHH', s)    
print(a)    #(b'B', b'M', 691256, 0, 54, 40, 640, 360, 1, 24)    
            
#结果显示,b'B'、b'M'说明是Windows位图,位图大小为640x360,颜色数24
4.格式字符串    
4.1.用途:在打包解包数据时指定数据类型;还有控制字节序,大小和对齐特殊字符    
    
4.2.字节序大小和对齐:    
    默认C以机器本机格式和字节序表示,在必要时跳过填充字节进行适当对齐
    或根据下表格式字符串首字符指示打包数据字节序大小和对齐方式

简表:

 

字符

字节序

Size

对齐

备注

@

native

native

native

用本机字节序

=

native

standard

none

用本机字节序,大小和对齐是标准化

<

little-endian

standard

none

 

>

big-endian

standard

none

 

!

network (=大端)

standard

none

网络字节序不确定时可采用

说明:
    无法指示非本机字节序(强制字节交换);只能使用适当 < 或 > 选项
    填充仅在连续结构成员之间自动添加。在编码结构开头或结尾没有添加填充
    使用非原生大小和对齐时不添加填充,例如使用 <,>,= 和 !
    要将结构末尾与特定类型对齐要求对齐,请用重复计数为零的该类型的代码结束格式
    标准尺寸仅取决于格式字符,请参阅格式字符部分中的表

备注:        
    1)本机字节序是big-endian或 little-endian取决于主机系统:
        Intel x86 和 AMD64(x86-64)是 little-endian
        摩托罗拉 68000 和 PowerPC G5 都是大端的;
        ARM 和 Intel Itanium 具有可切换字节序(双端)

    2)查看系统字节序:sys.byteorder
    3)使用 C 编译器的 sizeof 表达式确定 native size 和 alignment
          原生大小和对齐是使用C编译器sizeof表达式确定总是与本地字节顺序相结合
4.3.格式字符
含义:
    根据类型C和Python值之间转换应是显而易见 
    “标准大小”指用标准大小打包值大小(字节)即当格式字符串以 <,>,!= 开头
    用本机大小时,打包值大小取决于平台
    
简表:

 

格式

C类型

Python type

标准大小

备注

x

pad byte

no value

 

 

c

char

bytes长度1

1字节

 

b

signed char

integer

1字节

 

B

unsigned char

integer

1字节

 

?

_Bool

bool

1字节

类型不可用时用a进行模拟char;True,False,0,1

h

short

integer

2

 

H

unsigned short

integer

2

 

i

int

integer

4

 

I

unsigned int

integer

4

 

l

long

integer

4

 

L

unsigned long

integer

4

 

q

long long

integer

8

仅C编译器支持C转换代码在本地模式或在win

Q

unsigned long long

integer

8

同上

n

ssize_t

integer

 

仅用于本机大小(默认或@)。对于标准大小,可用适任何整数格式

N

size_t

integer

 

同上

e

 

float

2

binary16 C不支持用uint替换

f

float

float

4

binary32

d

double

float

8

binary64不管平台使用浮点格式

s

char[]

bytes

 

 

p

char[]

bytes

 

 

P

void *

integer

 

仅用于本地字节序(默认或@)不能用'='

 

说明:

    1)'4h'==” 'hhhh'格式字符串前整数表示重复计数
    2)'10s'表示10字节字符串(被解释为字节长度)'10c'表示10个字符
    3)格式间空格被忽略; 计数及其格式不能包含空格

    4)对于打包,字符串将被截断或填充为空字节,以使其合适
          对于解包,结果字节对象总是具有指定字节数。特殊'0s'表示单一空字符串( '0c'表示0个字符)

    5)当值x用整数格式(一个'b', 'B','h','H','i','I','l','L', 'q','Q'),如x在有效范围之外抛异常

    6)'p'存储在一很短可变长度字符串固定数目字节,由计数给出。
        存储第一字节是字符串长度或255,以较小者为准。字符串字节在后面。
        如传入字符串 pack()太长(比计数减1更长)则仅count-1存储字符串前导字节。
        如字符串小于 count-1则填充空字节,以便使用所有字节中精确计数字节。

        注意对于unpack()中,'p'格式字符占用count字节,但返回字符串不能包含超过255个字节