社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python struct库:5分钟学会读懂任何二进制文件

A逍遥之路 • 1 年前 • 440 次点击  

今天来分享这个"神奇"的struct库,它能让你轻松处理各种二进制文件。

struct库到底是干什么的?

简单说,struct库就是Python和二进制数据之间的"翻译官"。

你知道吗?计算机里的所有文件,不管是图片、音频、视频还是游戏存档,本质上都是一堆0和1组成的二进制数据。而struct库就能帮我们把这些看不懂的二进制数据,转换成我们能理解的数字、字符串等。

反过来,它也能把我们的数据"打包"成二进制格式保存到文件里。

基础用法:pack和unpack

1. 打包数据(pack)

import struct
# 把整数和浮点数打包成二进制数据data = struct.pack('if'12343.14)print(data)  # b'\xd2\x04\x00\x00\xc3\xf5H@'print(len(data))  # 8字节

这里的'if'是格式字符串:

  • 'i' 表示一个4字节的整数

  • 'f' 表示一个4字节的浮点数

2. 解包数据(unpack)

import struct
# 假设我们有一些二进制数据binary_data = b'\xd2\x04\x00\x00\xc3\xf5H@'
# 解包出原来的数据num, pi = struct.unpack('if', binary_data)print(f"整数: {num}")    # 整数: 1234print(f"浮点数: {pi}")   # 浮点数: 3.140000104904175

实战应用:读取BMP图片的基本信息

想知道一张BMP图片的宽度和高度吗?用struct库几行代码就搞定:

import struct
def read_bmp_info(filename):    with open(filename, 'rb'as f:        # 读取BMP文件头(前54字节)        header = f.read(54)
        # 检查是否是BMP文件        if header[:2] != b'BM':            print("这不是BMP文件!" )            return
        # 从第18字节开始读取宽度和高度(各4字节)        width, height = struct.unpack(', header[18:26])
        print(f"图片宽度: {width} 像素")        print(f"图片高度: {height} 像素")
# 使用方法(需要有一个test.bmp文件)# read_bmp_info('test.bmp')

注意 中的 < 表示小端字节序,I 表示无符号整数。

解析网络数据包

如果你对网络编程感兴趣,struct在解析网络协议时特别有用:

import struct
def parse_ip_header(packet_data):    # 解析IP数据包头部(简化版)    # 前20字节包含IP头部信息    ip_header = struct.unpack('!BBHHHBBH4s4s', packet_data[:20])
    version = ip_header[0] >> 4  # IP版本    protocol = ip_header[6]      # 协议类型    src_ip = ip_header[8]        # 源IP(二进制)    dst_ip = ip_header[9]        # 目标IP(二进制)
    print(f"IP版本: {version}")    print(f"协议: {protocol}")
    # 将二进制IP转换为可读格式    import socket    src_ip_str = socket.inet_ntoa(src_ip)    dst_ip_str = socket.inet_ntoa(dst_ip)
    print(f"源IP: {src_ip_str}")    print(f"目标IP: {dst_ip_str}")
# 这个函数需要真实的网络数据包才能测试

处理传感器数据

假设你有一个温湿度传感器,每次发送8字节的数据:

import structimport time
def simulate_sensor_data():    """模拟传感器发送的二进制数据"""    temperature = 25.6  # 温度    humidity = 60.3     # 湿度    timestamp = int(time.time())  # 时间戳
    # 打包数据:2个浮点数 + 1个整数    data = struct.pack('ffi', temperature, humidity, timestamp)    return data
def parse_sensor_data(binary_data):     """解析传感器数据"""    temp, humid, ts = struct.unpack('ffi', binary_data)
    print(f"温度: {temp:.1f}°C")    print(f"湿度: {humid:.1f}%")    print(f"时间: {time.ctime(ts)}")
# 模拟数据传输sensor_data = simulate_sensor_data()print("收到传感器数据,正在解析...")parse_sensor_data(sensor_data)

常用格式字符速查表

格式字符C类型Python类型大小(字节)说明
bsigned charint1有符号字节
Bunsigned charint1 无符号字节
hshortint2短整型
Hunsigned shortint2无符号短整型
iintint4整型
Iunsigned intint4无符号整型
ffloatfloat4单精度浮点
ddoublefloat8双精度浮点
schar[]bytes-字符串

字节序说明

  • @ 或不写:本机字节序

  • =:本机字节序

  • <:小端字节序(Intel处理器常用)

  • >:大端字节序(网络字节序)

  • !:网络字节序(大端)

实用技巧

1. 计算结构体大小

import struct
# 计算格式字符串对应的字节数size = struct.calcsize('ifi')print(f"数据大小: {size} 字节")  # 12字节

2. 处理可变长度数据

import struct
def pack_string(text):    """打包字符串:先存长度,再存内容"""    text_bytes = text.encode('utf-8')    length = len(text_bytes)    return struct.pack(f'I{length}s', length, text_bytes)
def unpack_string(data):    """解包字符串"""    length = struct.unpack('I', data[:4])[0]    text_bytes = struct.unpack(f'{length}s', data[4:4+length])[0]    return text_bytes.decode('utf-8')
# 测试original = "Hello Python!"packed = pack_string(original)unpacked = unpack_string(packed)print(f"原文: {original}")print(f"解包后: {unpacked}")

错误处理

使用struct时要注意数据长度匹配:

import struct
try:    # 错误:数据长度不匹配    struct.unpack('ii'b'\x01\x02\x03')  # 需要8字节,只给了3字节except struct.error as e:    print(f"解包错误: {e}")
try:    # 正确的做法    data = b'\x01\x02\x03\x04\x05\x06\x07\x08'    result = struct.unpack('ii', data)    print(f"解包成功: {result}")except struct.error as e:    print(f"解包错误: {e}")

struct库看起来复杂,其实就做两件事:

  1. pack:把Python数据变成二进制

  2. unpack:把二进制变成Python数据

掌握了这两个函数,你就能:

  • 解析各种文件格式

  • 处理网络协议数据

  • 与C语言程序交换数据

  • 优化数据存储

学习建议

  1. 从简单开始:先练习整数和浮点数的打包解包

  2. 理解字节序:网络编程时特别重要

  3. 多做实验:用不同的格式字符串试试效果

  4. 结合实际:找个具体的文件格式来练手

转发、收藏、在看,是对作者最大的鼓励!👏
关注逍遥不迷路,Python知识日日补!






           对Python,AI,自动化办公提效,副业发展等感兴趣的伙伴们,扫码添加逍遥,限免交流群

备注【成长交流】

图片

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/184004