該模塊在Python值和表示為Python bytes對(duì)象的C結(jié)緩沖區(qū)構(gòu)體之間進(jìn)行轉(zhuǎn)換。可用于處理存儲(chǔ)在文件中或者來(lái)自網(wǎng)絡(luò)連接,以及其它來(lái)源的二進(jìn)制數(shù)據(jù)。它使用格式化字符串,作為C結(jié)構(gòu)體布局的簡(jiǎn)潔描述,以及從Python值,或者到Python值的預(yù)期轉(zhuǎn)換。
注意:默認(rèn)情況下,封裝給定的C結(jié)構(gòu)體的結(jié)構(gòu)包括填充字節(jié),以便為涉及的C類型保持正確的對(duì)齊;類似地,解包時(shí)會(huì)考慮對(duì)齊。選擇此行為使得被封裝的結(jié)構(gòu)體的字節(jié)完全對(duì)應(yīng)于C結(jié)構(gòu)體在內(nèi)存中的布局。要處理平臺(tái)無(wú)關(guān)的數(shù)據(jù)格式,或者忽略隱式的填充字節(jié),可以使用
standard大小和對(duì)齊,代替native大小和對(duì)齊,查看字節(jié)順序,大小和對(duì)齊了解詳情。
有幾個(gè)struct函數(shù)(和Struct的方法)接收一個(gè)buffer參數(shù)。它引用實(shí)現(xiàn)了Buffer協(xié)議的對(duì)象,并提供一個(gè)可讀,或可讀寫(xiě)的緩存。用于該目的的最常見(jiàn)的類型是bytes和bytearray,但是可以視為字節(jié)數(shù)組的許多其它類型實(shí)現(xiàn)了Buffer協(xié)議,因此它們可以讀和填充,而不需要額外的從bytes對(duì)象復(fù)制。
1 函數(shù)和異常
該模塊定義了以下異常和函數(shù):
1.1 異常 struct.error
在各種場(chǎng)合下拋出異常;參數(shù)是描述錯(cuò)誤的字符串。
1.2 struct.pack(fmt, v1, v2, ...)
根據(jù)格式化字符串fmt封裝,返回一個(gè)包括v1,v2等值的字節(jié)對(duì)象。參數(shù)必須與格式化所需的值完全匹配。
1.3 struct.pack_into(ftm, buffer, offset, v1, v2, ...)
根據(jù)格式化字符串fmt,封裝v1,v2等值,并從位置offset開(kāi)始,將封裝的字節(jié)寫(xiě)入可寫(xiě)緩沖區(qū)buffer中。注意,offset是必需的參數(shù)。
1.4 struct.unpack(fmt, buffer)
根據(jù)格式化字符串fmt,從緩沖區(qū)buffer(假設(shè)由pack(fmt, ...)封裝)中解包。即使結(jié)果只包含一項(xiàng),也是一個(gè)元組。緩沖區(qū)的大?。ㄒ宰止?jié)為單位)必需與格式所需的大小匹配,比如calcsize()所得的結(jié)果。
1.5 struct.unpack_from(fmt, buffer, offset=0)
根據(jù)格式化字符串fmt,從位置offset開(kāi)始解包。即使結(jié)果只包含一項(xiàng),也是一個(gè)元組。緩沖區(qū)的大小(以字節(jié)為單位)減去offset,至少是格式化所需的大小,比如calcsize()所得的結(jié)果。
1.5 struct.iter_unpack(fmt, buffer)
版本3.4中新增。
根據(jù)格式化字符串fmt,從緩沖區(qū)buffer中迭代解包。該函數(shù)返回一個(gè)iterator,它將從緩沖區(qū)中讀取大小相等的塊,直到所有內(nèi)容被耗盡。緩沖區(qū)的大小(以字節(jié)為單位)必須是格式化所需大小的倍數(shù),比如calcsize()所得的結(jié)果。
每次迭代yield一個(gè)由格式化字符串指定的元組。
1.6 struct.calcsize(fmt)
返回對(duì)應(yīng)于格式化字符串fmt的結(jié)構(gòu)體(以及由pack(fmt, ...)生成的字節(jié)對(duì)象)的大小。
2 格式化字符串
封裝和解包數(shù)據(jù)時(shí),格式化字符串是用于指定預(yù)期布局的機(jī)制。它們由Format Characters構(gòu)成,指定封裝和解包的數(shù)據(jù)類型。此外,還有一些特殊字符控制字節(jié)順序,大小和對(duì)齊。
2.1 字節(jié)順序,大小和對(duì)齊
默認(rèn)情況下,C語(yǔ)言類型以機(jī)器的本機(jī)格式和字節(jié)順序表示,如果需要(根據(jù)C編譯器使用的規(guī)則),跳過(guò)填充字節(jié),以便正確對(duì)齊。
或者根據(jù)下表,格式化字符串的第一個(gè)字符用于表明封裝數(shù)據(jù)的字節(jié)順序,大小和對(duì)齊:
| 字符 | 字節(jié)順序 | 大小 | 對(duì)齊 |
|---|---|---|---|
| @ | 本機(jī) | 本機(jī) | 本機(jī) |
| = | 本機(jī) | 標(biāo)準(zhǔn) | 無(wú) |
| < | 小端 | 標(biāo)準(zhǔn) | 無(wú) |
| > | 大端 | 標(biāo)準(zhǔn) | 無(wú) |
| ! | 網(wǎng)絡(luò)(等于大端) | 標(biāo)準(zhǔn) | 無(wú) |
如果第一個(gè)字符不是其中之一,則假定為“@”。
本地字節(jié)順序是大端或小端,這取決于主機(jī)系統(tǒng)。例如,Intel x86和AMD64(x86-64)是小端字節(jié)序;摩托羅拉68000和PowerPC G5是大端字節(jié)序;ARM和Intel Itanium可切換字節(jié)順序(雙字節(jié)順序)。使用sys.byteorder檢查系統(tǒng)的字節(jié)順序。
使用C編譯器的sizeof表達(dá)式確定本機(jī)大小和對(duì)齊。這總是與本機(jī)字節(jié)順序結(jié)合。
標(biāo)準(zhǔn)大小僅取決于格式化字符;參考格式化字符中的表格。
注意“@”和“=”之間的區(qū)別:都使用本機(jī)字節(jié)順序;但后者的大小和對(duì)齊是標(biāo)準(zhǔn)的。
“!”形式用于忘記網(wǎng)絡(luò)字節(jié)順序是大端還是小端的情況。
沒(méi)有辦法表示非本地字節(jié)順序(強(qiáng)制字節(jié)交換);使用適當(dāng)?shù)摹?lt;”或“>”。
注意:
- 填充僅在連續(xù)的結(jié)構(gòu)體成員之間自動(dòng)添加。在編碼的結(jié)構(gòu)體的開(kāi)頭或結(jié)尾不填充。
- 使用非本地大小和對(duì)齊時(shí),不添加填充,比如“<”,“>”,“=”和“!”。
- 要將結(jié)構(gòu)體結(jié)尾與特殊類型的對(duì)齊要求對(duì)齊,使用重復(fù)計(jì)數(shù)為0的該類型的代碼結(jié)束格式。
2.2 格式化字符
版本3.1中修改:在3.0中,有些整數(shù)格式封裝了超出范圍的值,并拋出
DeprecationWarning代替struct.error。版本3.2中修改:新增為非整數(shù)使用
__index__()方法。版本3.3中修改:添加“n”和“N”格式。
版本3.6中修改:添加“e”格式。
格式化字符有以下含義:C和Python值之間的轉(zhuǎn)換應(yīng)該明確指定類型?!皹?biāo)準(zhǔn)大小”列表示,使用標(biāo)準(zhǔn)大小時(shí),被封裝值的字節(jié)大??;也就是格式化字符串以“<”,“>”,“!”或“=”開(kāi)始時(shí)。當(dāng)使用本機(jī)大小,被封裝值的大小是平臺(tái)相關(guān)的。
| 格式 | C類型 | Python類型 | 標(biāo)準(zhǔn)大小 | 提示 |
|---|---|---|---|---|
| x | 填充字節(jié) | 沒(méi)有值 | ||
| c | char | 長(zhǎng)度為1的字節(jié) | 1 | |
| b | signed char | integer | 1 | 1,3 |
| B | unsigned char | integer | 1 | 3 |
| ? | _Bool | bool | 1 | 1 |
| h | short | integer | 2 | 3 |
| H | unsigned short | integer | 2 | 3 |
| i | int | integer | 4 | 3 |
| I | unsigned int | integer | 4 | 3 |
| l | long | integer | 4 | 3 |
| L | unsigned long | integer | 4 | 3 |
| q | long long | integer | 8 | 2,3 |
| Q | unsigned long long | integer | 8 | 2,3 |
| n | ssize_t | integer | 4 | |
| N | size_t | integet | 4 | |
| e | 7 | float | 2 | 5 |
| f | float | float | 4 | 5 |
| d | double | float | 8 | 5 |
| s | char[] | bytes | ||
| p | char[] | bytes | ||
| P | void * | integer | 6 |
提示:
- “?”轉(zhuǎn)換碼對(duì)應(yīng)的
_Bool類型由C99定義。如果該類型不可用,使用char模擬。在標(biāo)準(zhǔn)模式下,它總是由一個(gè)字節(jié)表示。 - 只有C編譯器支持
long long類型,或者Windows上的__int64時(shí),“q”和“Q”轉(zhuǎn)換碼才在本機(jī)模式下可用。在標(biāo)準(zhǔn)模式下它們總是可用。 - 使用圖任何整數(shù)轉(zhuǎn)換碼封裝一個(gè)非整數(shù)時(shí),如果非整數(shù)有
__index__()方法,則在封裝前會(huì)調(diào)用該方法把參數(shù)轉(zhuǎn)換為整數(shù)。 - “n”和“N”轉(zhuǎn)換只在本機(jī)大小中可用(選擇默認(rèn)或“@”字節(jié)順序)。對(duì)于標(biāo)準(zhǔn)大小,可用使用適合應(yīng)用程序的其它整數(shù)格式。
- 對(duì)于“f”,“d”和“e”轉(zhuǎn)換碼,封裝分別表示使用IEEE 754的binary32,binary64或binary16格式,而不管平臺(tái)使用的浮點(diǎn)數(shù)格式。
- “P”只在本機(jī)字節(jié)順序可用(選擇默認(rèn)或“@”字節(jié)順序)?!?”根據(jù)主機(jī)系統(tǒng)選擇使用小端或大端順序。
struct模塊不會(huì)解釋為本機(jī)順序,因此“P”格式不可用。 - IEEE 754標(biāo)準(zhǔn)的2008版本中,引入了IEEE 754 binary16半精度。它有一個(gè)符號(hào)位,5位指數(shù)和11位精度(其中10位存儲(chǔ)),全精度可用表示大約
6.1e-05和6.1e-05。C編譯器沒(méi)有廣泛支持該類型;在典型的機(jī)器中,unsigned short可用于存儲(chǔ),但不適合數(shù)據(jù)運(yùn)算。
可以在格式化字符之前使用整數(shù)表示重復(fù)次數(shù)。例如,“4h”完全等價(jià)于“hhhh”。
盡管次數(shù)和它的格式不可能包含空格,還是會(huì)忽略格式化字符之前的空格。
對(duì)于“s”格式化字符,次數(shù)表示字節(jié)的長(zhǎng)度,而不是其它格式化字符的重復(fù)次數(shù);例如,“10s”表示單個(gè)10個(gè)字節(jié)的字符串,“10c”表示10個(gè)字符。如果沒(méi)有指定次數(shù),默認(rèn)為1。對(duì)于封裝,字符串被截?cái)啵蛘哂每兆止?jié)填充,讓其正確適應(yīng)。對(duì)于解包,生成的字節(jié)對(duì)象總是指定的字節(jié)數(shù)。對(duì)于特殊情況,“0s”表示單個(gè)空字符串(“0c”表示0個(gè)字符)。
使用其中一個(gè)整數(shù)格式(“b”,“B”,“h”,“H”,“i”,“I”,“l(fā)”,“L”,“q”,“Q”)封裝值x的時(shí)候,如果x超出格式的有效返回,會(huì)拋出struct.error異常。
格式化字符“p”編碼一個(gè)Pascal string,表示一個(gè)short可變長(zhǎng)度的字符串存儲(chǔ)在固定字節(jié)數(shù)中,其長(zhǎng)度由次數(shù)指定。第一個(gè)字節(jié)存儲(chǔ)字符串的長(zhǎng)度,或者255,取兩者中的較小者。接著是字節(jié)的字符串。如果傳遞到pack()中的字符串太長(zhǎng)(長(zhǎng)于次數(shù)減1),則只存儲(chǔ)前count-1個(gè)字節(jié)。如果字符串比count-1短,則使用空字節(jié)填充,以便使用所有字節(jié)。注意,對(duì)應(yīng)unpack(),“p”格式化字符消耗count個(gè)字節(jié),但返回的字符串永遠(yuǎn)不會(huì)超過(guò)255個(gè)字節(jié)。
對(duì)于“?”格式化字符,返回值是True或False。封裝時(shí),使用參數(shù)對(duì)象的真值。在本機(jī)或標(biāo)準(zhǔn)bool表示中,0或1會(huì)被封裝,解包時(shí)任何非0值是True。
2.3 示例
注意:所有示例假設(shè)本機(jī)字節(jié)順序和大小,以及大端機(jī)器對(duì)齊。
封裝/解包三個(gè)整數(shù)的基本示例:
>>> 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ò)分配給變量,或者將結(jié)果包裝在命名元組中來(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)
格式化字符的順序可能會(huì)對(duì)大小有影響,因?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
下面的“11h01”格式,在結(jié)尾指定了兩個(gè)填充字節(jié),假設(shè)long在4字節(jié)邊界對(duì)齊:
>>> pack('11h01', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
這只在本機(jī)大小和對(duì)齊有效時(shí)才其作用;標(biāo)準(zhǔn)大小和對(duì)齊不強(qiáng)制任何對(duì)齊。
3 類
struct模塊還定義了以下類型:
3.1 類struct.Struct(format)
返回一個(gè)新的Struct對(duì)象,更具格式化字符串format寫(xiě)入和讀取二進(jìn)制數(shù)據(jù)。創(chuàng)建一個(gè)Struct對(duì)象,并調(diào)用它的方法,比用同樣格式調(diào)用struct函數(shù)更高效,因?yàn)楦袷交址恍枰幾g一次。
編譯的Struct對(duì)象支持以下方法和屬性:
3.1.1 pack(v1, v2, ...)
完全等同于pack()函數(shù),使用編譯后的格式。(len(result)將會(huì)等于size)
3.1.2 pack_into(buffer, offset, v1, v2, ...)
完全等同于pack_into()函數(shù),使用編譯后的格式。
3.1.3 unpack(buffer)
完全等同于unpack()函數(shù),使用編譯后的格式。緩沖區(qū)的大?。ㄒ宰止?jié)為單位)必須等于size。
3.1.4 unpack_from(buffer, offset=0)
完全等同于unpack_from()函數(shù),使用編譯后的格式。緩沖區(qū)的大小減去offset(以字節(jié)為單位)必須至少為size。
3.1.5 iter_unpack(buffer)
版本3.4中新增。
完全等同于iter_unpack()函數(shù),使用編譯后的格式。緩沖區(qū)的大?。ㄒ宰止?jié)為單位)必須是size的倍數(shù)。
3.1.6 format
構(gòu)造該Struct對(duì)象的格式化字符串。
3.1.7 size
對(duì)應(yīng)于format的結(jié)構(gòu)體(以及由pack(fmt, ...)生成的字節(jié)對(duì)象)的大小。