(Windows)Python 2.7 学习笔记 五十八 struct

2020-11-22 10:48:46

struct

准确地讲,Python没有专门处理字节的数据类型。但由于 str 既是字符串,又可以表示字节,所以,字节数组=str。而在C语言中,我们可以很方便地用struct、union来处理字节,以及字节和int,float的转换。

在Python中,比方说要把一个32位无符号整数变成字节,也就是4个长度的str,你得配合位运算符这么写:

>>> n = 10240099
>>> b1 = chr((n & 0xff000000) >> 24)
>>> b2 = chr((n & 0xff0000) >> 16)
>>> b3 = chr((n & 0xff00) >> 8)
>>> b4 = chr(n & 0xff)
>>> s = b1 + b2 + b3 + b4
>>> s
'\x00\x9c@c'
>>>

非常麻烦。如果换成浮点数就无能为力了。

好在Python提供了一个 struct 模块来解决 str 和其他二进制数据类型的转换。

struct 的 pack 函数把任意数据类型变成字符串:

>>> import struct
>>> struct.pack('>I', 10240099)
'\x00\x9c@c'
>>>

pack 的第一个参数是处理指令, ‘>I’ 的意思是:

表示字节顺序是big­endian,也就是网络序, I 表示4字节无符号整数。

后面的参数个数要和处理指令一致。

unpack 把 str 变成相应的数据类型:

>>> struct.unpack('>IH', '\xf0\xf0\xf0\xf0\x80\x80')
(4042322160L, 32896)
>>>

根据 >IH 的说明,后面的 str 依次变为 I :4字节无符号整数和 H :2字节无符号整数。

所以,尽管Python不适合编写底层操作字节流的代码,但在对性能要求不高的地方,利用 struct 就方便多了。

struct 模块定义的数据类型可以参考Python官方文档:

https://docs.python.org/2/library/struct.html#format­characters

Windows的位图文件(.bmp)是一种非常简单的文件格式,我们来用 struct 分析一下。

首先找一个bmp文件,没有的话用“画图”画一个。

读入前30个字节来分析:

参考:Python Struct读取bmp图片信息_zoujin6649的博客-CSDN博客


C:\Users\Administrator\Desktop>python
Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 bit (
AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import struct
>>>
>>> with open('test.bmp', 'rb') as f:
...     s = f.read(30)
...
>>> print(s)
BM顟
>>> s
'BM\xee\x91\x00\x00\x00\x00\x00\x00>\x00\x00\x00(\x00\x00\x00(\x02\x00\x00\x06\x
02\x00\x00\x01\x00\x01\x00'
>>>

BMP格式采用小端方式存储数据,文件头的结构按顺序如下:

两个字节: 'BM' 表示Windows位图, 'BA' 表示OS/2位图;
一个4字节整数:表示位图大小;
一个4字节整数:保留位,始终为0;
一个4字节整数:实际图像的偏移量;
一个4字节整数:Header的字节数;
一个4字节整数:图像宽度;
一个4字节整数:图像高度;
一个2字节整数:始终为1;
一个2字节整数:颜色数。

所以,组合起来用 unpack 读取:

>>> struct.unpack('<ccIIIIIIHH', s)
('B', 'M', 37358, 0, 62, 40, 552, 518, 1, 1)
>>>

结果显示, ‘B’ 、 ‘M’ 说明是Windows位图,位图大小为552×512,颜色数为1。

请编写一个 bmpinfo.py ,可以检查任意文件是否是位图文件,如果是,打印出图片大小和颜色数。

struct_bmp.py
# -*- coding:gbk -*-
 
import base64,struct
 
with open('test.bmp','rb') as f:
    s=f.read(30)
	
print(s)
 
def bmp_info():
    unpackbuf=struct.unpack('<ccIIIIIIHH',s)
    if (unpackbuf[0]!=b'B' or unpackbuf[1]!=b'M'):
        return None
    else:
        return {'width':unpackbuf[6],'height':unpackbuf[7],'color':unpackbuf[9]}
bi=bmp_info()
print(bi['width'],bi['height'],bi['color'])
C:\Users\Administrator\Desktop>python struct_bmp.py
BM顟
(552, 518, 1)

发表评论

zh_CNChinese