struct --- 將字節(jié)串解讀為打包的二進(jìn)制數(shù)據(jù)?

源代碼: Lib/struct.py


此模塊可以執(zhí)行 Python 值和以 Python bytes 對(duì)象表示的 C 結(jié)構(gòu)之間的轉(zhuǎn)換。 這可以被用來(lái)處理存儲(chǔ)在文件中或是從網(wǎng)絡(luò)連接等其他來(lái)源獲取的二進(jìn)制數(shù)據(jù)。 它使用 格式字符串 作為 C 結(jié)構(gòu)布局的精簡(jiǎn)描述以及與 Python 值的雙向轉(zhuǎn)換。

備注

默認(rèn)情況下,打包給定 C 結(jié)構(gòu)的結(jié)果會(huì)包含填充字節(jié)以使得所涉及的 C 類型保持正確的對(duì)齊;類似地,對(duì)齊在解包時(shí)也會(huì)被納入考慮。 選擇此種行為的目的是使得被打包結(jié)構(gòu)的字節(jié)能與相應(yīng) C 結(jié)構(gòu)在內(nèi)存中的布局完全一致。 要處理平臺(tái)獨(dú)立的數(shù)據(jù)格式或省略隱式的填充字節(jié),請(qǐng)使用 standard 大小和對(duì)齊而不是 native 大小和對(duì)齊:詳情參見(jiàn) 字節(jié)順序,大小和對(duì)齊方式。

某些 struct 的函數(shù)(以及 Struct 的方法)接受一個(gè) buffer 參數(shù)。 這將指向?qū)崿F(xiàn)了 緩沖協(xié)議 并提供只讀或是可讀寫緩沖的對(duì)象。 用于此目的的最常見(jiàn)類型為 bytesbytearray,但許多其他可被視為字節(jié)數(shù)組的類型也實(shí)現(xiàn)了緩沖協(xié)議,因此它們無(wú)需額外從 bytes 對(duì)象復(fù)制即可被讀取或填充。

函數(shù)和異常?

此模塊定義了下列異常和函數(shù):

exception struct.error?

會(huì)在多種場(chǎng)合下被引發(fā)的異常;其參數(shù)為一個(gè)描述錯(cuò)誤信息的字符串。

struct.pack(format, v1, v2, ...)?

返回一個(gè) bytes 對(duì)象,其中包含根據(jù)格式字符串 format 打包的值 v1, v2, ... 參數(shù)個(gè)數(shù)必須與格式字符串所要求的值完全匹配。

struct.pack_into(format, buffer, offset, v1, v2, ...)?

根據(jù)格式字符串 format 打包 v1, v2, ... 等值并將打包的字節(jié)串寫入可寫緩沖區(qū) bufferoffset 開(kāi)始的位置。 請(qǐng)注意 offset 是必需的參數(shù)。

struct.unpack(format, buffer)?

根據(jù)格式字符串 format 從緩沖區(qū) buffer 解包(假定是由 pack(format, ...) 打包)。 結(jié)果為一個(gè)元組,即使其只包含一個(gè)條目。 緩沖區(qū)的字節(jié)大小必須匹配格式所要求的大小,如 calcsize() 所示。

struct.unpack_from(format, /, buffer, offset=0)?

對(duì) buffer 從位置 offset 開(kāi)始根據(jù)格式字符串 format 進(jìn)行解包。 結(jié)果為一個(gè)元組,即使其中只包含一個(gè)條目。 緩沖區(qū)的字節(jié)大小從位置 offset 開(kāi)始必須至少為 calcsize() 顯示的格式所要求的大小。

struct.iter_unpack(format, buffer)?

根據(jù)格式字符串 format 以迭代方式從緩沖區(qū) buffer 解包。 此函數(shù)返回一個(gè)迭代器,它將從緩沖區(qū)讀取相同大小的塊直至其內(nèi)容全部耗盡。 緩沖區(qū)的字節(jié)大小必須整數(shù)倍于格式所要求的大小,如 calcsize() 所示。

每次迭代將產(chǎn)生一個(gè)如格式字符串所指定的元組。

3.4 新版功能.

struct.calcsize(format)?

返回與格式字符串 format 相對(duì)應(yīng)的結(jié)構(gòu)的大小(亦即 pack(format, ...) 所產(chǎn)生的字節(jié)串對(duì)象的大?。?。

格式字符串?

格式字符串是用來(lái)在打包和解包數(shù)據(jù)時(shí)指定預(yù)期布局的機(jī)制。 它們使用指定被打包/解包數(shù)據(jù)類型的 格式字符 進(jìn)行構(gòu)建。 此外,還有一些特殊字符用來(lái)控制 字節(jié)順序,大小和對(duì)齊方式。

字節(jié)順序,大小和對(duì)齊方式?

默認(rèn)情況下,C類型以機(jī)器的本機(jī)格式和字節(jié)順序表示,并在必要時(shí)通過(guò)跳過(guò)填充字節(jié)進(jìn)行正確對(duì)齊(根據(jù)C編譯器使用的規(guī)則)。

或者,根據(jù)下表,格式字符串的第一個(gè)字符可用于指示打包數(shù)據(jù)的字節(jié)順序,大小和對(duì)齊方式:

字符

字節(jié)順序

大小

對(duì)齊方式

@

按原字節(jié)

按原字節(jié)

按原字節(jié)

=

按原字節(jié)

標(biāo)準(zhǔn)

無(wú)

<

小端

標(biāo)準(zhǔn)

無(wú)

>

大端

標(biāo)準(zhǔn)

無(wú)

!

網(wǎng)絡(luò)(=大端)

標(biāo)準(zhǔn)

無(wú)

如果第一個(gè)字符不是其中之一,則假定為 '@'

本機(jī)字節(jié)順序可能為大端或是小端,取決于主機(jī)系統(tǒng)的不同。 例如, Intel x86 和 AMD64 (x86-64) 是小端的;Motorola 68000 和 PowerPC G5 是大端的;ARM 和 Intel Itanium 具有可切換的字節(jié)順序(雙端)。 請(qǐng)使用 sys.byteorder 來(lái)檢查你的系統(tǒng)字節(jié)順序。

本機(jī)大小和對(duì)齊方式是使用 C 編譯器的 sizeof 表達(dá)式來(lái)確定的。 這總是會(huì)與本機(jī)字節(jié)順序相綁定。

標(biāo)準(zhǔn)大小僅取決于格式字符;請(qǐng)參閱 格式字符 部分中的表格。

請(qǐng)注意 '@''=' 之間的區(qū)別:兩個(gè)都使用本機(jī)字節(jié)順序,但后者的大小和對(duì)齊方式是標(biāo)準(zhǔn)化的。

形式 '!' 代表網(wǎng)絡(luò)字節(jié)順序總是使用在 IETF RFC 1700 中所定義的大端序。

沒(méi)有什么方式能指定非本機(jī)字節(jié)順序(強(qiáng)制字節(jié)對(duì)調(diào));請(qǐng)正確選擇使用 '<''>'。

注釋:

  1. 填充只會(huì)在連續(xù)結(jié)構(gòu)成員之間自動(dòng)添加。 填充不會(huì)添加到已編碼結(jié)構(gòu)的開(kāi)頭和末尾。

  2. 當(dāng)使用非本機(jī)大小和對(duì)齊方式即 '<', '>', '=', and '!' 時(shí)不會(huì)添加任何填充。

  3. 要將結(jié)構(gòu)的末尾對(duì)齊到符合特定類型的對(duì)齊要求,請(qǐng)以該類型代碼加重復(fù)計(jì)數(shù)的零作為格式結(jié)束。 參見(jiàn) 例子。

格式字符?

格式字符具有以下含義;C 和 Python 值之間的按其指定類型的轉(zhuǎn)換應(yīng)當(dāng)是相當(dāng)明顯的。 ‘標(biāo)準(zhǔn)大小’列是指當(dāng)使用標(biāo)準(zhǔn)大小時(shí)以字節(jié)表示的已打包值大?。灰簿褪钱?dāng)格式字符串以 '<', '>', '!''=' 之一開(kāi)頭的情況。 當(dāng)使用本機(jī)大小時(shí),已打包值的大小取決于具體的平臺(tái)。

格式

C 類型

Python 類型

標(biāo)準(zhǔn)大小

備注

x

填充字節(jié)

無(wú)

c

char

長(zhǎng)度為 1 的字節(jié)串

1

b

signed char

整數(shù)

1

(1), (2)

B

unsigned char

整數(shù)

1

(2)

?

_Bool

bool

1

(1)

h

short

整數(shù)

2

(2)

H

unsigned short

整數(shù)

2

(2)

i

int

整數(shù)

4

(2)

I

unsigned int

整數(shù)

4

(2)

l

long

整數(shù)

4

(2)

L

unsigned long

整數(shù)

4

(2)

q

long long

整數(shù)

8

(2)

Q

unsigned long long

整數(shù)

8

(2)

n

ssize_t

整數(shù)

(3)

N

size_t

整數(shù)

(3)

e

(6)

float

2

(4)

f

float

float

4

(4)

d

double

float

8

(4)

s

char[]

字節(jié)串

p

char[]

字節(jié)串

P

void*

整數(shù)

(5)

在 3.3 版更改: 增加了對(duì) 'n''N' 格式的支持

在 3.6 版更改: 添加了對(duì) 'e' 格式的支持。

注釋:

  1. '?' 轉(zhuǎn)換碼對(duì)應(yīng)于 C99 定義的 _Bool 類型。 如果此類型不可用,則使用 char 來(lái)模擬。 在標(biāo)準(zhǔn)模式下,它總是以一個(gè)字節(jié)表示。

  2. 當(dāng)嘗試使用任何整數(shù)轉(zhuǎn)換碼打包一個(gè)非整數(shù)時(shí),如果該非整數(shù)具有 __index__() 方法,則會(huì)在打包之前調(diào)用該方法將參數(shù)轉(zhuǎn)換為一個(gè)整數(shù)。

    在 3.2 版更改: 增加了針對(duì)非整數(shù)使用 __index__() 方法的特性。

  3. 'n''N' 轉(zhuǎn)換碼僅對(duì)本機(jī)大小可用(選擇為默認(rèn)或使用 '@' 字節(jié)順序字符)。 對(duì)于標(biāo)準(zhǔn)大小,你可以使用適合你的應(yīng)用的任何其他整數(shù)格式。

  4. 對(duì)于 'f', 'd''e' 轉(zhuǎn)換碼,打包表示形式將使用 IEEE 754 binary32, binary64 或 binary16 格式 (分別對(duì)應(yīng)于 'f', 'd''e'),無(wú)論平臺(tái)使用何種浮點(diǎn)格式。

  5. 'P' 格式字符僅對(duì)本機(jī)字節(jié)順序可用(選擇為默認(rèn)或使用 '@' 字節(jié)順序字符)。 字節(jié)順序字符 '=' 選擇使用基于主機(jī)系統(tǒng)的小端或大端排序。 struct 模塊不會(huì)將其解讀為本機(jī)排序,因此 'P' 格式將不可用。

  6. IEEE 754 binary16 "半精度" 類型是在 IEEE 754 標(biāo)準(zhǔn) 的 2008 修訂版中引入的。 它包含一個(gè)符號(hào)位,5 個(gè)指數(shù)位和 11 個(gè)精度位(明確存儲(chǔ) 10 位),可以完全精確地表示大致范圍在 6.1e-056.5e+04 之間的數(shù)字。 此類型并不被 C 編譯器廣泛支持:在一臺(tái)典型的機(jī)器上,可以使用 unsigned short 進(jìn)行存儲(chǔ),但不會(huì)被用于數(shù)學(xué)運(yùn)算。 請(qǐng)參閱維基百科頁(yè)面 half-precision floating-point format 了解詳情。

格式字符之前可以帶有整數(shù)重復(fù)計(jì)數(shù)。 例如,格式字符串 '4h' 的含義與 'hhhh' 完全相同。

格式之間的空白字符會(huì)被忽略;但是計(jì)數(shù)及其格式字符中不可有空白字符。

對(duì)于 's' 格式字符,計(jì)數(shù)會(huì)被解析為字節(jié)的長(zhǎng)度,而不是像其他格式字符那樣的重復(fù)計(jì)數(shù);例如,'10s' 表示一個(gè) 10 字節(jié)的字節(jié)串,而 '10c' 表示 10 個(gè)字符。 如果未給出計(jì)數(shù),則默認(rèn)值為 1。 對(duì)于打包操作,字節(jié)串會(huì)被適當(dāng)?shù)亟財(cái)嗷蛱畛淇兆止?jié)以符合要求。 對(duì)于解包操作,結(jié)果字節(jié)對(duì)象總是恰好具有指定數(shù)量的字節(jié)。 作為特殊情況,'0s' 表示一個(gè)空字符串(而 '0c' 表示 0 個(gè)字符)。

當(dāng)使用某一種整數(shù)格式 ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q') 打包值 x 時(shí),如果 x 在該格式的有效范圍之外則將引發(fā) struct.error。

在 3.1 版更改: 在之前版本中,某些整數(shù)格式包裝了超范圍的值并會(huì)引發(fā) DeprecationWarning 而不是 struct.error。

'p' 格式字符用于編碼“Pascal 字符串”,即存儲(chǔ)在由計(jì)數(shù)指定的 固定長(zhǎng)度字節(jié) 中的可變長(zhǎng)度短字符串。 所存儲(chǔ)的第一個(gè)字節(jié)為字符串長(zhǎng)度或 255 中的較小值。 之后是字符串對(duì)應(yīng)的字節(jié)。 如果傳入 pack() 的字符串過(guò)長(zhǎng)(超過(guò)計(jì)數(shù)值減 1),則只有字符串前 count-1 個(gè)字節(jié)會(huì)被存儲(chǔ)。 如果字符串短于 count-1,則會(huì)填充空字節(jié)以使得恰好使用了 count 個(gè)字節(jié)。 請(qǐng)注意對(duì)于 unpack(),'p' 格式字符會(huì)消耗 count 個(gè)字節(jié),但返回的字符串永遠(yuǎn)不會(huì)包含超過(guò) 255 個(gè)字節(jié)。

對(duì)于 '?' 格式字符,返回值為 TrueFalse。 在打包時(shí)將會(huì)使用參數(shù)對(duì)象的邏輯值。 以本機(jī)或標(biāo)準(zhǔn) bool 類型表示的 0 或 1 將被打包,任何非零值在解包時(shí)將為 True。

例子?

備注

所有示例都假定使用一臺(tái)大端機(jī)器的本機(jī)字節(jié)順序、大小和對(duì)齊方式。

打包/解包三個(gè)整數(shù)的基礎(chǔ)示例:

>>>
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8

解包的字段可通過(guò)將它們賦值給變量或?qū)⒔Y(jié)果包裝為一個(gè)具名元組來(lái)命名:

>>>
>>> record = b'raymond   \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)

>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond   ', serialnum=4658, school=264, gradelevel=8)

格式字符的順序可能對(duì)大小產(chǎn)生影響,因?yàn)闈M足對(duì)齊要求所需的填充是不同的:

>>>
>>> pack('ci', b'*', 0x12131415)
b'*\x00\x00\x00\x12\x13\x14\x15'
>>> pack('ic', 0x12131415, b'*')
b'\x12\x13\x14\x15*'
>>> calcsize('ci')
8
>>> calcsize('ic')
5

以下格式 'llh0l' 指定在末尾有兩個(gè)填充字節(jié),假定 long 類型按 4 個(gè)字節(jié)的邊界對(duì)齊:

>>>
>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'

這僅當(dāng)本機(jī)大小和對(duì)齊方式生效時(shí)才會(huì)起作用;標(biāo)準(zhǔn)大小和對(duì)齊方式并不會(huì)強(qiáng)制進(jìn)行任何對(duì)齊。

參見(jiàn)

模塊 array

被打包為二進(jìn)制存儲(chǔ)的同質(zhì)數(shù)據(jù)。

模塊 xdrlib

打包和解包 XDR 數(shù)據(jù)。

?

struct 模塊還定義了以下類型:

class struct.Struct(format)?

返回一個(gè)新的 Struct 對(duì)象,它會(huì)根據(jù)格式字符串 format 來(lái)寫入和讀取二進(jìn)制數(shù)據(jù)。 一次性地創(chuàng)建 Struct 對(duì)象并調(diào)用其方法相比使用同樣的格式調(diào)用 struct 函數(shù)更為高效,因?yàn)檫@樣格式字符串只需被編譯一次。

備注

傳遞給 Struct 和模塊層級(jí)函數(shù)的已編譯版最新格式字符串會(huì)被緩存,因此只使用少量格式字符串的程序無(wú)需擔(dān)心重用單獨(dú)的 Struct 實(shí)例。

已編譯的 Struct 對(duì)象支持以下方法和屬性:

pack(v1, v2, ...)?

等價(jià)于 pack() 函數(shù),使用了已編譯的格式。 (len(result) 將等于 size。)

pack_into(buffer, offset, v1, v2, ...)?

等價(jià)于 pack_into() 函數(shù),使用了已編譯的格式。

unpack(buffer)?

等價(jià)于 unpack() 函數(shù),使用了已編譯的格式。 緩沖區(qū)的字節(jié)大小必須等于 size。

unpack_from(buffer, offset=0)?

等價(jià)于 unpack_from() 函數(shù),使用了已編譯的格式。 緩沖區(qū)的字節(jié)大小從位置 offset 開(kāi)始必須至少為 size

iter_unpack(buffer)?

等價(jià)于 iter_unpack() 函數(shù),使用了已編譯的格式。 緩沖區(qū)的大小必須為 size 的整數(shù)倍。

3.4 新版功能.

format?

用于構(gòu)造此 Struct 對(duì)象的格式字符串。

在 3.7 版更改: 格式字符串類型現(xiàn)在是 str 而不再是 bytes。

size?

計(jì)算出對(duì)應(yīng)于 format 的結(jié)構(gòu)大?。ㄒ嗉?pack() 方法所產(chǎn)生的字節(jié)串對(duì)象的大?。?。