通常,在这样的"二进制格式"中,给一些数据加上前缀长度的目的是为了让解包代码知道有多少数据。 但是,使用struct.unpack不可能一次性解包所有内容--因为struct模块使用的格式是"提前计算"的。这在打包端很好,因为所有数据都可用。但在解包端不起作用,因为信息需要动态发现。 换句话说:当我们解压缩像b'\x00\x01-'这样的数据时,* 知道它是用OP示例代码中的方法压缩的 *,我们不能预先创建一个对数据正确的格式字符串。要创建这个字符串,我们需要长度,但长度是 * in data *。
6条答案
按热度按时间xuo3flqw1#
通常你不会使用
struct.pack
把长度头和值放在一起,而是直接使用struct.pack(">h", len(data))
,通过线路发送(例如在网络协议中),然后发送数据,不需要创建新的字节缓冲区。在您的情况下,您可以简单地执行以下操作:
但正如我所说,如果您有一个基于套接字的应用程序,它将是这样的:
44u64gxh2#
下面是长度和字符串的打包:
因此,当您解包时,应该期望返回两个值,即长度和字符串:
一般来说,如果你不知道字符串是如何打包的,那么就没有万无一失的方法来恢复数据,你只能猜测了!
如果你知道数据是由字符串的长度和字符串本身组成的,那么你可以尝试试错法:
有可能组成一个不明确的字符串
t
,它有多个有效的解包,这将导致不同的string2
,但是,我不确定。3bygqnnd3#
struct
模块是为固定格式的数据块设计的。但是,您可以使用以下代码:dba5bblo4#
假设
data
是一大块字节,并且您已经成功解析出了前posn
个字节,该字节块的文档说明下一项是一个字节串,前面是一个16位有符号整数(不太可能,但您确实说过h
)。下面是该怎么做:
现在你已经准备好下一个项目了。
在Python 2.5及更高版本中,可以使用
unpack_from()
代替切片。goqiplq25#
通常,在这样的"二进制格式"中,给一些数据加上前缀长度的目的是为了让解包代码知道有多少数据。
但是,使用
struct.unpack
不可能一次性解包所有内容--因为struct
模块使用的格式是"提前计算"的。这在打包端很好,因为所有数据都可用。但在解包端不起作用,因为信息需要动态发现。换句话说:当我们解压缩像
b'\x00\x01-'
这样的数据时,* 知道它是用OP示例代码中的方法压缩的 *,我们不能预先创建一个对数据正确的格式字符串。要创建这个字符串,我们需要长度,但长度是 * in data *。struct.unpack_from
因此,不可避免地,我们将需要进行两次单独的尝试来读取数据。由于我们只想考虑部分数据,因此我们使用
struct.unpack_from
而不是struct.unpack
。最简单的方法如下:1.从头开始解压缩前两个字节,以找出长度。
1.使用该长度,解压缩任意多个字节,也就是说,从刚好在长度计数之后开始。
如文档中所述:
一个六个一x一个七个一x一个八个一x * 一个九个一x * 一个十个一x
根据格式字符串 * format *,从位置 * offset * 开始的 * buffer * 解包。结果是一个元组,即使它只包含一个项。从位置 * offset * 开始的缓冲区大小(以字节为单位)必须至少为格式所需的大小,如
calcsize()
所反映。因此:
注意结尾逗号:这些用于解包元组(不是在结构解包意义上,而是由
struct.unpack_from
返回的native Python sense)。当然,第二次调用中的
2
说明了第一次解压缩的数据量,对于更一般的情况,或者如果这看起来太神奇,可以通过对格式字符串调用struct.calcsize
来计算解压缩的数据量。历史记录
这个问题很久以前就提出了,当时可能还没有现代工具。
在Python 3.6之前,需要对字符串调用
.format
,而不是使用f字符串,来创建第二个格式字符串;因此,'{}s'.format(length)
。在Python 2.6之前,必须使用与OP:'%ds' % length
.在2.5之前,
struct.unpack_from
不可用。要解决此问题,请显式地对字符串进行适当的切片,然后使用unpack
:其他注意事项:流式传输数据以及一次处理一种类型的数据
当然,
struct
中的所有功能都需要在缓冲区中工作。(例如网络连接或以二进制模式打开的文件),则必须完全读取它才能使用struct.unpack
或struct.unpack_from
。这可能会浪费大量内存,并且考虑到我们无论如何都需要在两个单独的步骤中考虑数据,这是没有意义的。让我们对输入流建模:
由于每次读取都是并发的,我们不需要跟踪偏移量,而是每次读取适当数量的字节。使用
struct
模块:但是现在很明显,
struct
模块对于解释数据的任务来说是多余的,第一次读取的只是代表整数的几个字节;int
类型已经知道如何解释它。对于第二次读取,stream.read(length)
已经是所需的数据,因此没有理由进行任何更多的处理。fquxozlt6#
你到底要怎么拆包?
对于
unpack(fmt, string)
,len(string)
必须等于struct.calcsize(fmt)
,因此解压缩的数据不可能只是'-'
。但是:
现在您可以使用
data
。