admin 发表于 2018-1-1 23:11:11

用struct模块将二进制数据转换为python数据结构类型

    如你所见, Python 中有许多文本处理工具(模块、函数等),然而处理二进制数据的工具则要少得多。 标准库里有一个 struct 模块,专门用于处理类似 C 和 C++ 中结构体的数据。你可以使用 struct 模块的功能将二进制数据转换为 Python 中的数据结构。

   以一个 PNG 文件(一种常见的图片格式,其他图片格式还有 GIF、 JPEG 等)为例看看struct 是如何工作的。我们来编写一个小程序,从 PNG 文件中获得图片的宽度和高度信息。
   使用 O’Reilly 的经典标志:一只睁大了眼睛的眼镜猴,见下图。
               你可以在 Wikipedia(http://upload.wikimedia.org/wikipedia/en/9/95/O’Reilly_logo.png)上获取这张图片的 PNG 文件。第 8 章之前都不会讨论读取文件的方法,因此这里我仅仅是将这个文件下载下来, 并编写了一个简单的小程序将它的数据以字节形式打印出来,然后将起始的 30 字节数据存入 Pythonbytes 型变量 data 中,如下所示。方便起见,你只需复制这部分数据即可。(PNG 格式规定了图片的宽度和高度信息存储在初始 24 字节中,因此不需要其他的额外数据。)

   代码:import struct
valid_png_header = b'\x89PNG\r\n\x1a\n'
data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR' + \
    b'\x00\x00\x00\x9a\x00\x00\x00\x8d\x08\x02\x00\x00\x00\xc0'
if data[:8] == valid_png_header:
    width, height = struct.unpack('>LL', data)
    print('Valid PNG, width', width, 'height', height)
else:
    print('Not a valid PNG')输出结果:
Valid PNG, width 154 height 141
   以上代码说明:
• data 包含了 PNG 文件的前 30 字节内容,为了书的排版,我将这 30 字节数据放到了两行字节串中,并用 + 和续行符(\)将它们连接起来;
• valid_png_header 包含 8 字节序列,它标志着这是一个有效的 PNG 格式文件;
• width 值位于第 16~20 字节, height 值则位于第 21~24 字节。
   上面代码中的 >LL 是一个格式串,它用于指导 unpack() 正确解读字节序列并将它们组装成Python 中的数据类型。可以将它分解成下面几个基本格式标志:
• > 用于指明整数是以大端(big-endian)方案存储的;
• 每个 L 代表一个 4 字节的无符号长(unsigned long)整数。
   你可以直接获取 4 字节数据:
>>> data
b'\x00\x00\x00\x9a'
>>> data0x9a
b'\x00\x00\x00\x8d'
      大端方案将高字节放在左侧。由于宽度和高度都小于 255,因此它们存储在每一个 4 字节序列的最后一字节中。 不难验证,上面的十六进制数转换为十进制后与我们预期的数值(图片的宽和高)一致:>>> 0x9a
154
>>> 0x8d
141
      如果想要执行上述过程的逆过程,将 Python 数据转换为字节,可以使用 struct pack()函数:
>>> import struct
>>> struct.pack('>L', 154)
b'\x00\x00\x00\x9a'
>>> struct.pack('>L', 141)
b'\x00\x00\x00\x8d'

admin 发表于 2018-1-1 23:31:53

注意:合法的png图片已x89PNG开头,合法的gif文件由GIF89a开头。。。每种视频、音频、图片等多媒体文件都有自己固定的开头。练习:
检测一下上面的 gif 是否为合法的 GIF 文件?
>>> gif[:6] == b'GIF89a'
True
注意,我们使用 b 来定义一个字节串而不是 Unicode 字符串,你可以在字节之间做比较,但是不能用字符串和字节比较:
>>> gif[:6] == 'GIF89a'
False
>>> type(gif)
<class 'bytes'>
>>> type('GIF89a')
<class 'str'>
>>> type(b'GIF89a')
<class 'bytes'>


页: [1]
查看完整版本: 用struct模块将二进制数据转换为python数据结构类型