Struct模塊是python中用于處理二進(jìn)制數(shù)據(jù)的工具,主要功能是將基本數(shù)據(jù)類型打包為字節(jié)流或從字節(jié)流中解析出原始數(shù)據(jù)。1. 它的核心功能包括pack和unpack函數(shù),分別用于打包和解包數(shù)據(jù);2. 支持指定大小端格式(如>表示大端,
在 python 中處理二進(jìn)制數(shù)據(jù)時(shí),struct 模塊是一個(gè)非常實(shí)用的工具。它主要用于將 Python 的基本數(shù)據(jù)類型(如整數(shù)、浮點(diǎn)數(shù)等)轉(zhuǎn)換為對(duì)應(yīng)的字節(jié)流(bytes),或者反過(guò)來(lái),從字節(jié)流中解析出原始數(shù)據(jù)。
這在網(wǎng)絡(luò)通信、文件格式解析、協(xié)議開發(fā)等場(chǎng)景中特別有用。
struct 是什么?為什么用它?
struct 模塊的核心功能是 打包(pack)和解包(unpack) 數(shù)據(jù)。比如,你有一個(gè)整數(shù) 12345,想把它轉(zhuǎn)成 4 字節(jié)的二進(jìn)制形式發(fā)送出去,或者接收到一段字節(jié)流,需要從中提取出多個(gè)不同類型的數(shù)據(jù),這時(shí)候 struct 就派上用場(chǎng)了。
它的優(yōu)勢(shì)在于:
立即學(xué)習(xí)“Python免費(fèi)學(xué)習(xí)筆記(深入)”;
- 精確控制數(shù)據(jù)的大小端(endianness)
- 明確指定每個(gè)字段的類型和長(zhǎng)度
- 避免手動(dòng)計(jì)算偏移量和位操作
常見用法:pack 和 unpack
這兩個(gè)函數(shù)是最常用的。
pack:把數(shù)據(jù)打包成 bytes
import struct # 打包一個(gè)整數(shù)(i 表示 int,通常是 4 字節(jié)) data = struct.pack('i', 12345) print(data) # 輸出類似 b'x39x30x00x00'
格式字符串 ‘i’ 表示使用默認(rèn)的字節(jié)序(一般是小端)。如果你要指定大端或小端,可以加前綴:
- >:大端(Big-endian)
例如:
struct.pack('>i', 12345) # 大端 struct.pack('<i', 12345) # 小端
unpack:把 bytes 解包回原始值
value = struct.unpack('i', data) print(value) # 輸出 (12345,)
注意返回的是一個(gè)元組,即使只有一個(gè)值。
如果打包時(shí)用了特定字節(jié)序,解包時(shí)也要對(duì)應(yīng):
struct.unpack('>i', b'x00x00x30x39') # 正確解析為 12345
常用格式字符說(shuō)明
格式字符串決定了如何解釋數(shù)據(jù)。以下是一些常用格式字符:
格式符 | 類型 | 字節(jié)數(shù) |
---|---|---|
b | 有符號(hào)字節(jié)(int8) | 1 |
B | 無(wú)符號(hào)字節(jié)(uint8) | 1 |
h | 有符號(hào)短整型 | 2 |
H | 無(wú)符號(hào)短整型 | 2 |
i | 有符號(hào)整型 | 4 |
I | 無(wú)符號(hào)整型 | 4 |
f | 單精度浮點(diǎn)型 | 4 |
d | 雙精度浮點(diǎn)型 | 8 |
你還可以組合使用:
struct.pack('<if', 1, 2.0) # 打包一個(gè) int + float,共 8 字節(jié)
實(shí)際應(yīng)用:解析固定結(jié)構(gòu)的二進(jìn)制數(shù)據(jù)
假設(shè)你要解析一個(gè)自定義的二進(jìn)制協(xié)議頭,結(jié)構(gòu)如下:
- 2 字節(jié)命令碼(unsigned short)
- 4 字節(jié)長(zhǎng)度(unsigned int)
- 8 字節(jié)時(shí)間戳(unsigned long long)
你可以這樣寫:
header_format = '<HIL' # H=2字節(jié)無(wú)符號(hào)短整型,I=4字節(jié)無(wú)符號(hào)整型,L=8字節(jié)無(wú)符號(hào)長(zhǎng)整型 header_data = b'x01x00x0ax00x00x00x01x00x00x00x00x00x00x00' cmd, length, timestamp = struct.unpack(header_format, header_data) print(cmd, length, timestamp) # 輸出 1 10 1
這種結(jié)構(gòu)化的處理方式,在解析網(wǎng)絡(luò)協(xié)議、圖像/音頻文件頭等場(chǎng)景下非常常見。
注意事項(xiàng)和常見問(wèn)題
- 對(duì)齊問(wèn)題:struct 默認(rèn)會(huì)考慮 C 結(jié)構(gòu)體的對(duì)齊規(guī)則。如果你希望緊湊排列,可以在格式字符串前加 = 或者用 !(網(wǎng)絡(luò)順序)。
- 字節(jié)序選擇:網(wǎng)絡(luò)傳輸一般用大端(>),而 x86 架構(gòu)的機(jī)器本地存儲(chǔ)多用小端(
- 錯(cuò)誤處理:輸入的 bytes 長(zhǎng)度必須嚴(yán)格匹配格式字符串所需的長(zhǎng)度,否則會(huì)報(bào)錯(cuò)。
- 變長(zhǎng)字段處理:struct 不適合直接處理變長(zhǎng)字段,通常先用 struct 提取頭部信息,再根據(jù)長(zhǎng)度讀取后續(xù)內(nèi)容。
基本上就這些。struct 雖然看起來(lái)簡(jiǎn)單,但在實(shí)際處理二進(jìn)制數(shù)據(jù)時(shí)非常關(guān)鍵,理解好格式字符串和字節(jié)序,能讓你在很多底層操作中游刃有余。