51学通信论坛2017新版

标题: 用struct模块将二进制数据转换为python数据结构类型 [打印本页]

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

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

     代码:
  1. import struct
  2. valid_png_header = b'\x89PNG\r\n\x1a\n'
  3. data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR' + \
  4.     b'\x00\x00\x00\x9a\x00\x00\x00\x8d\x08\x02\x00\x00\x00\xc0'
  5. if data[:8] == valid_png_header:
  6.     width, height = struct.unpack('>LL', data[16:24])
  7.     print('Valid PNG, width', width, 'height', height)
  8. else:
  9.     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[16:20]
b'\x00\x00\x00\x9a'
>>> data[20:24]0x9a
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
注意:合法的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'>







欢迎光临 51学通信论坛2017新版 (http://bbs.51xuetongxin.com/) Powered by Discuz! X3