[转]Python使用struct处理二进制(pack和unpack用法)

这篇文章写的很好,所以无耻的转了。。

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

struct模块中最重要的三个函数是pack(), unpack(), calcsize()


#  按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)
pack(fmt, v1, v2, ...) 
 
# 按照给定的格式(fmt)解析字节流string,返回解析出来的tuple
unpack(fmt, string)       
 
# 计算给定的格式(fmt)占用多少字节的内存
calcsize(fmt)


上述fmt中,支持的格式为:

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)

注1.q和Q只在机器支持64位操作时有意思

注2.每个格式前可以有一个数字,表示个数

注3.s格式表示一定长度的字符串,4s表示长度为4的字符串,但是p表示的是pascal字符串

注4.P用来转换一个指针,其长度和机器字长相关

注5.最后一个可以用来表示指针类型的,占4个字节

为了同c中的结构体交换数据,还要考虑有的c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.定义如下:

CHARACTER

BYTE ORDER

SIZE

ALIGNMENT

@

native

native

native

=

native

standard

none

<

little-endian

standard

none

>

big-endian

standard

none

!

network (= big-endian)

standard

none

 < : Little-Endian就是低位字节排放在内存的低地址端(栈顶),高位字节排放在内存的高地址端(栈底)

>:Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

!: 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

 

请编写一个bmpinfo.py,可以检查任意文件是否是位图文件,如果是,打印出图片大小和颜色数# _*_ coding:utf-8_*_

import base64, struct


def bmp_info(data):
    t = struct.unpack('<2c6I2H', data[:30])  # 注意因为前面的解析格式只有30位,所以后面的byte串只取前30位,否则会出错;'<2c6I2H' == ‘<ccIIIIIIHH’
if t[0] == b'B' and t[1] == b'M':
        return {
            'width': t[6],
            'height': t[7],
            'color': t[-1]
        }
    else:
        print("%s is not a bmp file" % data)

# test
bmp_data = base64.b64decode('Qk1oAgAAAAAAADYAAAAoAAAAHAAAAAoAAAABABAAAAAAADICAAASCwAAEgsAAAAAAAAAAAAA/3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9/AHwAfAB8AHwAfAB8AHwAfP9//3//fwB8AHwAfAB8/3//f/9/AHwAfAB8AHz/f/9//3//f/9//38AfAB8AHwAfAB8AHwAfAB8AHz/f/9//38AfAB8/3//f/9//3//fwB8AHz/f/9//3//f/9//3//f/9/AHwAfP9//3//f/9/AHwAfP9//3//fwB8AHz/f/9//3//f/9/AHwAfP9//3//f/9//3//f/9//38AfAB8AHwAfAB8AHwAfP9//3//f/9/AHwAfP9//3//f/9//38AfAB8/3//f/9//3//f/9//3//fwB8AHwAfAB8AHwAfAB8/3//f/9//38AfAB8/3//f/9//3//fwB8AHz/f/9//3//f/9//3//f/9/AHwAfP9//3//f/9/AHwAfP9//3//fwB8AHz/f/9/AHz/f/9/AHwAfP9//38AfP9//3//f/9/AHwAfAB8AHwAfAB8AHwAfAB8/3//f/9/AHwAfP9//38AfAB8AHwAfAB8AHwAfAB8/3//f/9//38AfAB8AHwAfAB8AHwAfAB8/3//f/9/AHwAfAB8AHz/fwB8AHwAfAB8AHwAfAB8AHz/f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//38AAA==')
bi = bmp_info(bmp_data)
assert bi['width'] == 28
assert bi['height'] == 10
assert bi['color'] == 16
print('ok')