Python は struct を使用してバイナリを処理します (パックとアンパックの使用法)

高洛峰
リリース: 2018-05-14 14:54:24
オリジナル
1683 人が閲覧しました

ファイルへのアクセスやソケット操作など、バイナリデータを処理するために Python を使用する必要がある場合があります。このとき、Python の struct モジュールを使用して、C 言語で構造体を処理できます。 struct module 3 つの最も重要な関数は、pack()、unpack()、calcsize() です

pack(fmt, v1, v2, ...) 指定された形式 (fmt) に従って、データを文字列にカプセル化します (実際にはこれは、C 構造体のバイト フローに似ています)

UnPACK (FMT, String) は、指定された形式 (FMT) に基づいて、バイト実行文字列を分析し、解析された Tuple

calcsize (FMT) の計算を返します (FMT) ).fmt) はメモリのバイト数を占有します

struct でサポートされている形式は次のとおりです:

形式 C 型 Python バイト数

x パッドバイト 値なし 1

c 長さ 1 の char 文字列 1

b signed char integer 1

B unsigned char integer 1

? _Bool bool 1

h short integer 2

H unsigned short integer 2

i int integer 4

I unsigned int integer または long 4

l長整数4

L unsigned long long 4

q long long long 8

Q unsigned long long long 8

f float float 4

d double float 8

s char[] string 1

p char[] string 1

P void * long

注 1.q と Q は、マシンが 64 ビット動作をサポートしている場合にのみ興味深いです

注 2. 番号を示すために、各形式の前に数字を付けることができます

注 3.s 形式は特定の長さの文字列を表し、4s は長さ 4 の文字列を表しますが、p はパスカル文字列を表します

注 4。P はポインタの変換に使用され、その長さはマシン語の長さに関連します

注 5。最後のものは、ポインター Type を表すために使用でき、4 バイトを占有します

C の構造体とデータを交換するには、一部の C または C++ コンパイラーがバイト アライメントを使用することも考慮する必要があります。通常は 4 バイトの 32 ビット システムです。したがって、構造体はローカル マシンのバイト順序に従って変換され、その定義は次のようになります:

文字のバイト順序 サイズと配置

@@ネイティブ十分な4バイト= byteを使用したネイティブ標準使用

- リトルエンディアンの使用方法は、 '@ 5S6sif'example 1のように、それをFMTの最初の位置に置くことです。 :

構造は次のとおりです:

struct Header
{
    unsigned short id;
    char[4] tag;
    unsigned int version;
    unsigned int count;
}
ログイン後にコピー

上記の構造データはsocket.recvを通じて受信され、文字列sがあります。今度はそれを解析する必要があります。unpack()関数を使用できます:

import struct
id, tag, version, count = struct.unpack("!H4s2I", s)
ログイン後にコピー

上記のフォーマット文字列の ! は、データがネットワークから受信されるため、解析にネットワーク バイト オーダーを使用することを意味します。次の H は、符号なしの短い ID を表します。 4s は 4 バイトの長さの文字列を表し、2I は 2 つの unsigned int 型データを表します

1 回のアンパックを渡すだけで、情報が ID、タグ、バージョン、カウントに保存されます

同様に、これも非常に便利です。ローカル データを構造体形式にパックするには:

ss = struct.pack("!H4s2I", id, tag, version, count);
ログイン後にコピー

Pack 関数は、ID、タグ、バージョン、カウントを配置し、指定された形式に従ってヘッダーを構造体に変換します。ss は文字列 (実際には C 構造体に似たバイト ストリーム) になります。この文字列は、socket.send(ss) を通じて送信できます。

例2:

import struct
a=12.34
#将a变为二进制
bytes=struct.pack('i',a)
ログイン後にコピー

このとき、bytesは文字列stringであり、その文字列はバイト単位のaのバイナリ記憶内容と同じです。

次に、逆の操作を実行し、既存のバイナリ データ バイト (実際には文字列) を Python データ型に変換します:

#unpack はタプルを返すことに注意してください!!

a,=struct.unpack('i',bytes)
ログイン後にコピー

複数のデータで構成されている場合データは次のようになります:

a='hello'
b='world!'
c=2
d=45.123
bytes=struct.pack('5s6sif',a,b,c,d)
ログイン後にコピー

この時点のバイトはバイナリ形式のデータであり、binfile.write(bytes) などのファイルに直接書き込むことができます

その後、必要なときにそれを読み出すことができますそれを bytes=binfile.read()

し、struct.unpack():

a,b,c,d=struct.unpack('5s6sif',bytes)
ログイン後にコピー

を通じて Python 変数にデコードされます。「5s6sif」は fmt と呼ばれ、数字と文字で構成される書式設定された文字列です。5s は 5 文字を意味します文字列 2i は 2 つの整数などを表します。使用可能な文字と型は次のとおりです。ctype 表現は Python の型に 1 対 1 で対応します。

注: バイナリ ファイルの処理中に問題が発生しました

バイナリ ファイルを処理するときは、次のメソッドを使用する必要があります:

binfile=open(filepath,'rb')    
#读二进制文件
binfile=open(filepath,'wb')   
#写二进制文件
ログイン後にコピー

それでは、binfile=open(filepath,'r') の結果の違いは何でしょうか?

2 つの違いがあります:

まず、「r」を使用するときに「0x1A」に遭遇すると、それはファイルの終わり、つまり EOF とみなされます。 「rb」を使用すると、この問題は発生しません。つまり、バイナリで書き込み、テキストで読み出す場合、「0X1A」が存在するとファイルの一部だけが読み出されます。 「rb」を使用すると、ファイルの最後まで読み取られます。

2 番目に、文字列 x=’abcndef’ の場合、len(x) を使用して長さを 7 にします。n を改行文字と呼び、実際には「0X0A」です。テキストモードである「w」で記述すると、「0X0A」は Windows プラットフォーム上で自動的に「0X0D」、「0X0A」の 2 文字に変更されます。つまり、実際のファイル長は 8 になります。 「r」テキスト モードで読み取ると、元の改行文字に自動的に変換されます。書き込み時に「wb」バイナリモードに変更すると、1文字は変更されず、読み取り時にそのまま読み込まれます。したがって、テキスト モードで書き込み、バイナリ モードで読み取る場合は、この余分なバイトを考慮する必要があります。 「0X0D」は復帰文字とも呼ばれます。 Linux では変化しません。 Linux は改行を表すために「0X0A」のみを使用するためです。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!