模組 struct資料打包

2021-06-16 23:29:38 字數 4035 閱讀 7499

有的時候需要用python處理二進位制資料,比如:訪問檔案.這時候,可以使用python的struct模組來完成.可以用 struct來處理c語言中的結構體.

注:此篇是貼上gala的部落格進行了一點點修改(基本是就是加了一些幫助我理解的注釋)

struct模組中最重要的三個函式是pack(), unpack(), calcsize()

pack(fmt, v1, v2, ...)     按照給定的格式(fmt),把資料封裝成字串(實際上是類似於c結構體的位元組流)

unpack(fmt, string)       按照給定的格式(fmt)解析位元組流string,返回解析出來的tuple

calcsize(fmt)                 計算給定的格式(fmt)占用多少位元組的記憶體

struct中支援的格式如下表:

format

c type

python

位元組數x

pad byte

no value1c

char

string of length 11b

signed

char

integer1b

unsigned

char

integer1?

_bool

bool1h

short

integer2h

unsigned

short

integer2i

intinteger4i

unsigned

intinteger or long4l

long

integer4l

unsigned

long

long4q

long

long

long8q

unsigned

long

long

long8f

float

float4d

double

float8s

char

string1p

char

string1p

void

*long

注1.q和q只在機器支援64位操作時有意思

注2.每個格式前可以有乙個數字,表示個數

注3.s格式表示一定長度的字串,4s表示長度為4的字串,但是p表示的是pascal字串

注4.p用來轉換乙個指標,其長度和機器字長相關

注5.最後乙個可以用來表示指標型別的,佔4個位元組

為了同c中的結構體交換資料,還要考慮有的c或c++編譯器使用了位元組對齊,通常是以4個位元組為單位的32位系統,故而struct根據本地機器位元組順序轉換.可以用格式中的第乙個字元來改變對齊方式.定義如下:

character

byte order

size and alignment

@native

native            湊夠4個位元組

=native

standard        按原位元組數

<

little-endian

standard        按原位元組數

>

big-endian

standard       按原位元組數

!network (= big-endian)

standard       按原位元組數

使用方法是放在fmt的第乙個位置,就像'@5s6sif'

示例一:

比如有乙個結構體

struct header

通過socket.recv接收到了乙個上面的結構體資料,存在字串s中,現在需要把它解析出來,可以使用unpack()函式.

import struct

id, tag, version, count = struct.unpack("!h4s2i", s)

上面的格式字串中,!表示我們要使用網路位元組順序解析,因為我們的資料是從網路中接收到的,在網路上傳送的時候它是網路位元組順序的.後面的h表示 乙個unsigned short的id,4s表示4位元組長的字串,2i表示有兩個unsigned int型別的資料.

就通過乙個unpack,現在id, tag, version, count裡已經儲存好我們的資訊了.

同樣,也可以很方便的把本地資料再pack成struct格式.

ss = struct.pack("!h4s2i", id, tag, version, count);

pack函式就把id, tag, version, count按照指定的格式轉換成了結構體header,ss現在是乙個字串(實際上是類似於c結構體的位元組流),可以通過 socket.send(ss)把這個字串傳送出去.

示例二:

import struct

a=12.34           #這裡是a是float,所以下面應該是用f,而不是i

#將a變為二進位制

bytes=struct.pack('i',a)     #用i的話解包以後就是12了      bytes=struct.pack('f',a)

此時bytes就是乙個string字串,字串按位元組同a的二進位制儲存內容相同。

再進行反操作

現有二進位制資料bytes,(其實就是字串),將它反過來轉換成python的資料型別:

a,=struct.unpack('i',bytes)     #a,=struct.unpack('j',bytes) 但是輸出的並不是12.54,而是12.53999·····這樣的極度接近12.54的數

注意,unpack返回的是tuple

所以如果只有乙個變數的話:

bytes=struct.pack('i',a)

那麼,解碼的時候需要這樣

a,=struct.unpack('i',bytes) 或者 (a,)=struct.unpack('i',bytes)

如果直接用a=struct.unpack('i',bytes),那麼 a=(12.34,) ,是乙個tuple而不是原來的浮點數了。

如果是由多個資料構成的,可以這樣:

a='hello'

b='world!'

c=2d=45.123

bytes=struct.pack('5s6sif',a,b,c,d)

此時的bytes就是二進位制形式的資料了,可以直接寫入檔案比如 binfile.write(bytes)

然後,當我們需要時可以再讀出來,bytes=binfile.read()

再通過struct.unpack()解碼成python變數

a,b,c,d=struct.unpack('5s6sif',bytes)

'5s6sif'這個叫做fmt,就是格式化字串,由數字加字元構成,5s表示佔5個字元的字串,2i,表示2個整數等等,下面是可用的字元及型別,ctype表示可以與python中的型別一一對應。

注意:二進位制檔案處理時會碰到的問題

我們使用處理二進位制檔案時,需要用如下方法

binfile=open(filepath,'rb')    讀二進位制檔案

binfile=open(filepath,'wb')    寫二進位制檔案

那麼和binfile=open(filepath,'r')的結果到底有何不同呢?

不同之處有兩個地方:

第一,使用'r'的時候如果碰到'0x1a',就會視為檔案結束,這就是eof。使用'rb'則不存在這個問題。即,如果你用二進位制寫入再用文字讀出的話,如果其中存在'0x1a',就只會讀出檔案的一部分。使用'rb'的時候會一直讀到檔案末尾。

第二,對於字串x='abc\ndef',我們可用len(x)得到它的長度為7,\n我們稱之為換行符,實際上是'0x0a'。當我們用'w'即文字方式寫的時候,在windows平台上會自動將'0x0a'變成兩個字元'0x0d','0x0a',即檔案長度實際上變成8.。當用'r'文字方式讀取時,又自動的轉換成原來的換行符。如果換成'wb'二進位制方式來寫的話,則會保持乙個字元不變,讀取時也是原樣讀取。所以如果用文字方式寫入,用二進位制方式讀取的話,就要考慮這多出的乙個位元組了。'0x0d'又稱回車符。linux下不會變。因為linux只使用'0x0a'來表示換行。

Python中使用struct模組打包二進位制資料

執行環境 python3.4.3 demo.py f open s data.bin wb import struct s b allen data struct.pack i5si 7,s,8 print data f.write data f.close a,b,c struct.unpack ...

struct 模組 subprocess 模組

struct 模組 就這麼用 import struct 首先匯入此模組 res ncjewgfjsdbvdhj 隨意的值 print len res 15 只是為了展示原res的長度res1 struct.pack i len res 打包,固定i模式,len res print len res1...

Python模組學習 struct 資料格式轉換

darkbull python是一門非常簡潔的語言,對於資料型別的表示,不像其他語言預定義了許多態別 如 在c 中,光整型就定義了8種 它只定義了六種基本型別 字串,整數,浮點數,元組,列表,字典。通過這六種資料型別,我們可以完成大部分工作。但當python需要通過網路與其他的平台進行互動的時候,必...