簡體   English   中英

從BytesIO到struct.unpack的慣用法?

[英]Idiomatic way to struct.unpack from BytesIO?

我有一些字節數據想要被解析為流,因為序列中較早的字節控制下游字節的解釋。 所以BytesIO看起來像我想要的東西。 但我也想使用struct模塊提供的功能。 但是struct的接口不是流式的。 是否有一種聰明/慣用的方式來嫁給這兩個人?

舉例來說,這是一個示例數據塊:

b'\n\x00\x02\x90\x10\x00\n\x00\x02`\x10\x00\n\x00\x02\x80\x10\x00'

我想把前4個字節拉成無符號大端int(例如struct.unpack(fmt='>I' )。因為下一個字節是0x10,我知道應該再多一個字節,結果是0x00然后它重新開始,讀取下一個4(0x0A000290),清洗,沖洗,重復。緊跟在每個4字節id之后的字節,觸發各種下游讀取(一些字節,一些短路)。

我可以做的事情

stream = b'\n\x00\x02\x90\x10\x00\n\x00\x02`\x10\x00\n\x00\x02\x80\x10\x00'
while stream:
    id = struct.unpack('>I', stream[:4])
    stream = stream[4:]
    ...

但這似乎不夠優雅。

我通常做的是:

def unpack(stream, fmt):
    size = struct.calcsize(fmt)
    buf = stream.read(size)
    return struct.unpack(fmt, buf)

例如:

>>> b = io.BytesIO(b'\n\x00\x02\x90\x10\x00\n\x00\x02`\x10\x00\n\x00\x02\x80\x10\x00')
>>> print(unpack(b, '>I'))
(167772816,)
>>> print(unpack(b, '>I'))
(268438016,)
>>> print(unpack(b, '>I'))
(39849984,)
>>> print(unpack(b, '>I'))
(167772800,)
>>> print(unpack(b, '>H'))
(4096,)

如果你想知道你是否消耗了整個流,你總是可以這樣做:

buf = stream.read(1)
if buf:
    raise ValueError("Stream not consumed")

但是調用你已經使用的相同函數可能更簡單:

>>> def ensure_finished(stream):
...     try:
...         unpack(stream, 'c')
...     except struct.error:
...         pass
...     else:
...         raise ValueError('Stream not consumed')
>>> ensure_finished(b)

如果您使用的流可能read的數量少於請求的字節數,那么您將需要使用while循環來繼續讀取和追加,直到EOF或者您獲得足夠的字節數。 否則,這就是你所需要的。

使用struct s buffer API:

buf = b'\n\x00\x02…'
offset = 0
id = struct.unpack_from('>I', buf, offset); offset += 4
⋮
x = struct.unpack_from('…', buf, offset)

如果你想避免在每次操作后聲明偏移量,你可以寫一個小包裝器,如下所示:

class unpacker(object):
    def __init__(self, buf):
        self._buf = buf
        self._offset = 0
    def __call__(self, fmt):
        result = struct.unpack_from(fmt, self._buf, self._offset)
        self._offset += struct.calcsize(fmt)
        return result

⋮

unpack = unpacker(buf)
id = unpack('>I')
⋮
x = unpack('…')

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM