Python struct.pack()函数(将Python数据转换为字节串,便于二进制数据的文件存储和网络传输)(格式字符串)(网络字节序、大端序、小端序、序列化)>B B H H

文章目录

  • Python struct.pack() 函数详解
  • 简介
  • 功能原理
  • 格式字符
  • 常见用途
  • 1. 网络通信:在网络通信中,数据需要被序列化为字节串才能进行传输。`struct.pack()` 提供了一种方便的方式来将各种数据类型转换成字节串。
  • 2. 文件存储:在写入二进制文件时,可以使用 `struct.pack()` 将需要存储的数据转换为字节串。
  • 示例代码
  • 打包整数
  • 打包浮点数
  • 示例
  • 解释
  • 打包多种数据类型
  • 高级应用
  • 字节对齐和填充
  • 使用网络字节序
  • 结论
  • 其他示例
  • 示例1:ModbusRTU报文组包`>B B H H`
  • Python struct.pack() 函数详解

    简介

    struct.pack() 是 Python 标准库中 struct 模块的一个函数,主要用于将 Python 数据转换为字节串,这些字节串符合特定的格式,便于二进制数据的存储和网络传输。此功能在处理网络通信和二进制文件时尤为重要。

    功能原理

    struct.pack() 函数通过格式字符串指定预期的结构,按照指定格式将 Python 数据(如数字、字符串、布尔值等)打包成字节串。格式字符串为一系列的格式字符,每个字符代表一种数据类型,同时决定了数据在编码后的二进制表示。

    格式字符

    下表列出了一些常用的格式字符,以及它们对应的数据类型和字节大小:

    格式字符 数据类型 标准大小
    b signed char 1
    B unsigned char 1
    h short 2
    H unsigned short 2
    i int 4
    I unsigned int 4
    f float 4
    d double 8
    s char[] 1

    常见用途

    1. 网络通信:在网络通信中,数据需要被序列化为字节串才能进行传输。struct.pack() 提供了一种方便的方式来将各种数据类型转换成字节串。
    2. 文件存储:在写入二进制文件时,可以使用 struct.pack() 将需要存储的数据转换为字节串。

    示例代码

    以下是一些 struct.pack() 的基本用法示例,展示如何将不同类型的数据打包成字节串。

    打包整数
    import struct
    
    # 打包一个整数
    result = struct.pack('i', 1024)
    print(result)  # 输出:b'\x00\x04\x00\x00'(在小端字节序的系统中)
    
    打包浮点数
    示例
    # 打包一个浮点数
    result = struct.pack('f', 3.14)
    print(result)  # 输出类似:b'\xc3\xf5H@'(具体输出可能因系统而异)
    
    解释

    输出结果是以16进制表示的二进制数据。在Python中,当你使用 struct.pack() 函数将数据(如浮点数)打包成字节串时,返回的字节串中的每个字节会以16进制的形式显示,每对16进制数字代表一个字节。例如,b'\xc3\xf5H@' 中:

  • \xc3 表示一个字节,16进制的 C3 是它的值。
  • \xf5 也是一个字节,16进制的 F5 是它的值。
  • H@ 是这个字节串可打印字符的直接显示。当字节的值在ASCII可打印字符的范围内(0x20到0x7E),它们就以字符形式显示。
  • 这种表示方式允许你直观地看到数据在内存中的二进制表示,这对于调试和处理需要精确数据表示的应用(如网络通信或文件格式定义)非常有用。

    理解字节串 b'\xc3\xf5H@' 如何代表浮点数 3.14 需要涉及到浮点数在计算机中的存储方式,具体为 IEEE 754
    标准。这个标准定义了浮点数的二进制表示格式,其中单精度(float,通常占用4字节)的浮点数的布局如下:

  • 符号位:1位,决定数值的正负。
  • 指数位:8位,决定数值的大小范围。
  • 尾数位:23位,存储实际数字信息。
  • 3.14 转换为二进制格式时,计算机会按照上述规则将其转换成对应的二进制序列。在大多数系统中(假定使用 IEEE 754
    标准和小端字节序),浮点数 3.14 的二进制表示大致过程如下:

    1. 将3.14转换为IEEE 754格式的二进制表示

    2. 3.14的二进制近似表示为 11.00100011110101110000101(这里只显示了部分尾数位,实际上有更多)。
    3. 将这个二进制数标准化后,得到 1.100100011110101110000101 x 2^1
    4. 符号位为0(因为是正数)。
    5. 指数位为 1 + 127 = 128(127是偏移量),二进制表示为 10000000
    6. 尾数位为 100100011110101110000101(忽略前面的隐含的1)。
    7. 整合符号位、指数位和尾数位

    8. 组合成:0 | 10000000 | 100100011110101110000101
    9. 转换为十六进制

    10. 这个32位的二进制数转换为十六进制,通常你会得到类似 4048F5C3 的形式,但实际上具体值会根据处理器架构的不同而略有不同。在小端序架构中,字节顺序会反转,所以可能显示为 C3F54840
    11. 在Python中的显示

    12. 在Python中,使用 struct.pack('f', 3.14) 打包时,默认使用小端序,因此十六进制的字节顺序可能显示为 b'\xc3\xf5H@'

    理解这个过程需要一定的底层二进制和内存表示知识。每个步骤中的具体值和表示可能根据使用的系统和编程环境(如编译器或解释器的具体实现)略有不同。

    打包多种数据类型
    # 打包多种数据类型
    result = struct.pack('iif', 1024, 2048, 3.14)
    print(result)  # 输出类似:b'\x00\x04\x00\x00\x00\x08\x00\x00\xc3\xf5H@'
    

    高级应用

    字节对齐和填充

    在打包结构体时,有时需要对齐字节以符合特定的内存对齐要求。struct.pack() 通过在格式字符串前加上对齐符,可以实现这一功能。

    # 4字节对齐
    result = struct.pack('iif', 1024, 2048, 3.14)
    print(result)  # 输出将根据对齐符而可能不同
    
    使用网络字节序

    网络传输时常常需要数据以网络字节序(大端序)进行序列化。可以通过在格式字符串前加 ! 实现这一点。

    # 使用网络字节序
    result = struct.pack('!iif', 1024, 2048, 3.14)
    print(result)  # 输出字节序为大端序
    

    结论

    struct.pack() 是一个强大的工具,适用于需要数据打包为二进制格式的多种场景。通过合理使用格式字符和对齐方式,可以有效地处理各种数据类型的序列化问题。

    其他示例

    示例1:ModbusRTU报文组包>B B H H

    def build_request_06(self, device_id: int, start_address: int, value: int) -> bytes:
        """
        构建写单个寄存器(功能码 06)的 Modbus RTU 请求。
        Args:
            device_id (int): 设备 ID。
            start_address (int): 起始地址。
            value (int): 寄存器的值。
        Returns:
            bytes: 完整的 Modbus RTU 请求数据,包括 CRC 校验。
        """
        header_format = '>B B H H'
        header = struct.pack(header_format,
                             device_id,
                             6,
                             start_address,
                             value)
        request = header
        request += self.crc16(request)
        return request
    

    解释:

    在Python的 struct.pack 函数中,字符串 '>B B H H' 用于定义如何将数据转换为字节。这个格式字符串包含两部分:字节顺序/对齐和类型代码。下面解释这个字符串中的每一个部分:

    1. >:这个符号代表 “big-endian” 字节顺序。big-endian 是一种在内存中排列多字节数据类型(如整数、浮点数)的方法,其中最重要的字节(最高位字节)存储在最低的内存地址上。这种格式在网络通信中非常常见,因为它是网络传输标准的一部分。

    2. B:表示一个无符号字符(unsigned char),占用1个字节。在这个上下文中,B 用于表示单字节的数值,如设备 ID 或功能码。

    3. H:表示一个无符号短整数(unsigned short),占用2个字节。在这里,它用于表示需要更多字节(如两个)的数值,例如起始地址和寄存器的值。

    因此,当你看到 '>B B H H' 时,它指的是:

  • 第一个 B:设备ID,1个字节
  • 第二个 B:功能码,1个字节
  • 第一个 H:起始地址,2个字节
  • 第二个 H:寄存器的值,2个字节
  • 这种格式确保了当你构建一个Modbus RTU请求时,各个部分都将按照预期的大小和顺序被正确地打包成字节流。

    作者:Dontla

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python struct.pack()函数(将Python数据转换为字节串,便于二进制数据的文件存储和网络传输)(格式字符串)(网络字节序、大端序、小端序、序列化)>B B H H

    发表回复