python3 struct.pack 以字符串为参数

python3 struct.pack with strings as parameters

我真的很想知道 python3 的 struct.pack 行为,但也许我错过了什么。

我正在通过 UDP 提交一个 .jpg 文件。顺便说一句:当我尝试一次提交整个文件 (~200kB) 时,socket.sendTo()sendAll() 函数抛出 "Python IOError: [Errno 90] Message too long"。所以我以 1024 字节为单位提交文件。没问题,我只是想知道为什么我在 python 文档中找不到关于此大小限制的

无论如何,我的主要问题是:我需要 struct.pack 在每段的开头放置一些信息 -> 2 个固定大小的字符串。

但当我这样做时

chunk = struct.pack("!3c4cI", bytes("JPG", "utf-8"), bytes(dev_id, "utf-8"), i)

它"struct.error: pack expected 8 items for packing (got 3)"

所以我得走了

chunk = struct.pack("!3c4ci", b"J", b"P", b"G", 
    bytes(dev_id[0:1], "utf-8"),
    bytes(dev_id[1:2], "utf-8"),
    bytes(dev_id[2:3], "utf-8"),
    bytes(dev_id[3:4], "utf-8"), i)

让它发挥作用。这是为什么!?

struct.pack 要求每个项目都作为单独的参数传递。此外 Python 区分 charbyte,即使在 C 中它们是同义词,这就是为什么 [=16] 需要一个字节的 bytes 值=],而不是 0 .. 255 范围内的整数。

不过,struct也支持s格式说明符,其中s代表给定长度的字符串:

>>> dev_id, i = 'R2D2', 42
>>> struct.pack("!3s4sI", b"JPG", dev_id.encode(), i)
b'JPGR2D2\x00\x00\x00*'

或者,如果您至少使用 Python 3.5,那么由于 PEP 448 -- Additional Unpacking Generalizations,您可以使用 B(无符号byte) 格式与 splat 运算符 * 结合使用,如下所示:

>>> struct.pack("!3B4BI", *b"JPG", *dev_id.encode(), i)

* 在这里所做的是将给定 bytes 值的每个字节作为 0 ... 255 范围内的整数解压缩到单独的参数中;如果 dev_id.encode() 产生 4 个 UTF-8 字节,那么总共 8 个参数将被传递给 struct.pack。与 c 不同,B 接受单个字节值作为整数。


P.S。请注意,我直接使用 b'JPG' 而不是调用 bytes('JPG', 'UTF-8'),并且同样在默认情况下在 UTF-8 中编码的字符串上调用 .encode(),以缩短代码。