51学通信论坛2017新版

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 4732|回复: 1
打印 上一主题 下一主题

[Python语言及其应用] 用struct模块将二进制数据转换为python数据结构类型

[复制链接]

 成长值: 15613

  • TA的每日心情
    开心
    2022-7-17 17:50
  • 2444

    主题

    2544

    帖子

    7万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    74104
    跳转到指定楼层
    楼主
    发表于 2018-1-1 23:11:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
        如你所见, 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 字节中,因此不需要其他的额外数据。)  

         代码:
    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'  

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    回复

    使用道具 举报

     成长值: 15613

  • TA的每日心情
    开心
    2022-7-17 17:50
  • 2444

    主题

    2544

    帖子

    7万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    74104
    沙发
     楼主| 发表于 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'>


    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    Archiver|手机版|小黑屋|51学通信技术论坛

    GMT+8, 2025-1-31 12:26 , Processed in 0.153820 second(s), 31 queries .

    Powered by Discuz! X3

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表