python序列化模块struct_python的struct模块
Python中缺少類似C語言structs這樣直接對字節序列進行序列化和反序列化的語法,作為一門腳本語言這是不必要的,但作為一門完整的編程語言必須提供這樣的能力,否則不能獨立的處理二進制文件和數據流。struct模塊即為處理這類問題而誕生。
要處理字節序需要三個能力:首先是字節和變量值的互相轉化,其次是字節序序問題,最后是數據對其的處理。
python中的基本變量類型有限,分別為int,float,bool類型。并且根據不同的運行環境所占用的長度不確定,這點跟C語言完全沒法比。因此模塊中我們需要提供一個確定變量和字節長度的轉換方法,也就是struct模塊中的 Format Characters。還有字節序的問題,Inter x86 和AMD64 系列主機都是小尾數,而網絡字節序是大尾數的字節序,并且有時我們要處理一份二進制文件事先并不知道其是大尾數還是小尾數表示,這些都需要開發人員去指定,因此需要提供對字節序的控制,在struct中也有對應的處理 Byte Order。 最后就是數據對其的處理,我們知道C語言中為了更有效的處理struct類型會進行對其處理,例如結構體 Student代碼如下,如果按照基本類型計算 一個char占用一個字節,兩個int共占用8個自己,應該是9個字節的長度,但實際占用了12個字節。C編譯器在處理如下結構體時一般按4字節對齊,這樣在gender和class_id之間會有3個字節用于對齊。
struct Student{
char gender;
int class_id;
int age;
};
int main(int argc, const char * argv[]) {
// insert code here...
printf("length of int %ld\n",sizeof(int));
printf("length of Student %ld\n",sizeof(Student));
return 0;
}
>> output
length of int 4
length of Student 12
struct 模塊中將對其與字節序控制結合在一起,通過結構化字符串的首字符控制,如下:
字符
字節序
是否sizeof對其
@
本機
是
=
本機
否
>
小尾數
否
<
大尾數
否
!
網絡字節序(大尾數)
否
@ 是默認字符,如果結構化字符串沒有字節序控制符則默認為@。
接下來看變量和字節轉換控制符有哪些:
符號
C 類型
Python 類型
字節長度
x
對其位
-
-
c
char
長度為1的 bytes 字符串
1
b
signed char
int
1
B
unsigned char
int
1
?
_Bool
bool
1
h
short
int
2
H
unsigned short
int
2
i
int
int
4
I
unsigned int
int
4
l
long
int
4
L
unsigned long
int
4
q
long long
int
4
Q
unsigned long long
int
4
n
ssize_t
int
-
N
size_t
int
-
e
半精度浮點數(c不支持)
float
2
f
float
float
4
d
double
float
8
s
char[]
bytes
-
p
char[]
bytes
-
P
void *
bytes
-
struct通過格式化字符串將字節和變量互轉,格式化字符串由上述的字節序字符+格式化字符組成,且字節序字符可省略。例如: >hhl 表示兩個short 和一個long。
>>> 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)
連續的格式化字符可以通過數字簡寫,>hhl完全等價與 >2hl。
上例中pack和unpack是struct模塊中的兩個方法,分別表示將變量值轉換為二進制字符串和從二進制字符串中轉換出變量值。在struct模塊中有4個基本的轉換函數、一個批量轉換的迭代器方法和一個計算長度的函數:
struct.pack(format, v1, v2, ...) # 打包
struct.pack_into(format, buffer, offset, v1, v2, ...)
struct.unpack(format, buffer) # 解碼
struct.unpack_from(format, buffer, offset=0)
如上4個基本轉換函數,其中pack和unpack是一對,pack將v1,v2的值按照format的格式轉化為二進制字符串,unpack將二進制字符串buffer按照format的格式轉換一元組。pack_into和unpack_into是一對,pack_into將v1,v2的值轉換成的二進制依次放入buffer中offset開始的位置。unpack_into則從buffer的offset開始轉換出變量值。
struct.calcsize(format)
calcsize方法類似于C語言中sizeof(Struct) 用于計算format具體占用多少字符。
struct.iter_unpack(format, buffer)
iter_unpack以迭代方式轉換buffer中的字節,每次都會讀取并轉化calcsize(format)長度的字節。
以上都是對struct模塊中功能的介紹,為了更清楚的看怎么使用,還是需要例子。
1、使用基礎的pack/unpack打包三個int型變量
>>> 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
上述代碼與官網代碼中format字符串不同,加了個>符號,因為在mac操作系統python 2.7 的環境中c編譯的long占用8個字節因此l長度為8。整個結果并按住8位對其,pack結果為:'\x01\x00\x02\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'。
2、unpack 的結果可以直接通過變量接受,也可以使用命名元組。
>>> 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)
3、由于對其的原因,格式化字符的位置可能影響結構化的長度。
>>> 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
struct 模塊不會對末尾的字符對其,如上c表示一個字節,在C語言中一個結構體不論先寫int還是char最終長度都為8,但是struct模塊中不同。如果想要結尾的字符也對其,需要用接下來的方法。
4、結尾使用 0 + 格式化字符的方式來結尾對其
>>> pack('llh', 1, 2, 3)
b'\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00'
>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
格式字符串llh最后的h占用2位,而格式字符串llh0l共占用12位
5、數字 + c和數字 + s的區別
>>> scbytes = b'abcde'
>>> unpack('5s',scbytes)
(b'abcde',)
>>> unpack('5c',scbytes)
(b'a', b'b', b'c', b'd', b'e')
>>>
可見 數字+c的方式解碼出5個長度為1的字符串,而數字+s的方式解碼出長度為5的一個字符串
除了直接使用函數的方式打包和解碼,struct模塊也支持使用類的方式。類定義如下:
class struct.Struct(format)
pack(v1, v2, ...)
pack_into(buffer, offset, v1, v2, ...)
unpack(buffer)
unpack_from(buffer, offset=0)
iter_unpack(buffer)
format
size
類定義包含五個方法和兩個屬性,其中五個方法與模塊中的方法一致。而size屬性則是calcsize方法的體現。
>>> record=b'raymond \x32\x12\x08\x01\x08'
>>> ray = Struct('<10sHHb')
>>> ray.unpack(record)
(b'raymond ', 4658, 264, 8)
>>> ray.pack(b'raymond ', 4658, 264, 8)
b'raymond 2\x12\x08\x01\x08'
總結
以上是生活随笔為你收集整理的python序列化模块struct_python的struct模块的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: md5后得到的32位字符串存储到mysq
- 下一篇: 的有效性最好_世界前10名面膜补水排行榜