Python : struct モジュールでバイナリ入出力

phiary に引っ越しました. 毎日プログラミングやWebに関する情報を発信しています! RSS 登録してたまに覗いたり, tweet やハテブして拡散してもらえると幸いです.

Pocket

バイナリデータの入出力は Python の struct モジュールを使えばかなり楽に行うことができます. エンディアン方式はフォーマット文字列の先頭に記号を変えるだけで切り替えられますし, バイナリ化 は pack メソッドで , 解読は unpack メソッドで簡単にできます.

フォーマットの指定方法はこちらを参照. ちなみに 4H と HHHH は同じ意味になります.

FLOW

  1. struct モジュールをインポート
  2. Struct クラスを生成(引数に構造のフォーマットを渡す)
  3. Struct.pack メソッドを呼び出してバイナリ化したいデータを渡す
  4. バイナリ化されたデータが返り値として渡されます.

SAMPLE

いくつかサンプルを作ってみました.

バイナリサンプル

# coding: utf-8
# バイナリサンプル

import struct, binascii

# ----------------------------------------------------------------
# 値
# ----------------------------------------------------------------
values = (1, b'ab', 2.7)
# struct を作成
s = struct.Struct("I 2s f")

# ----------------------------------------------------------------
# パックする
# ----------------------------------------------------------------
packed_value     = s.pack(*values)

# ----------------------------------------------------------------
# アンパックする
# ----------------------------------------------------------------
unpacked_value   = s.unpack(packed_value)

# ----------------------------------------------------------------
# 表示
# ----------------------------------------------------------------
print("Format String :", s.format)
print("Original Value:", values)
print("Packed Value  :", packed_value)
print("0xPacked Value:", binascii.hexlify(packed_value))
print("Size          :", s.size, "bytes")
print("Unpacked Value:", unpacked_value)

""" 実行結果
Format String : b'I 2s f'
Original Value: (1, b'ab', 2.7)
Packed Value  : b'\x01\x00\x00\x00ab\x00\x00\xcd\xcc,@'
0xPacked Value: b'0100000061620000cdcc2c40'
Size          : 12 bytes
Unpacked Value: (1, b'ab', 2.700000047683716)
"""
    

スプライトっぽいデータをバイナリ化してみる

# coding: utf-8
# スプライトっぽいデータをバイナリ化してみる

import struct, binascii

# ----------------------------------------------------------------
# スプライトっぽいデータを作成
# ----------------------------------------------------------------
sprite = {
          "pos"     : [32, 64],
          "size"    : [100, 200],
          "scale"   : [1, 1],
          "color"   : [255, 0, 0, 255],
          "visible" : True,
          "rotation": 0,
          "name"    : "palyer"
          }

# ----------------------------------------------------------------
# スプライトの値をリスト化
# ----------------------------------------------------------------
values = []
values.extend(sprite["pos"])
values.extend(sprite["size"])
values.extend(sprite["scale"])
values.extend(sprite["color"])
values.append(int(sprite["visible"]))
values.append(sprite["rotation"])
values.append(sprite["name"].encode())

# ----------------------------------------------------------------
# スプライトのデータをパックする
# ----------------------------------------------------------------
s = struct.Struct("< 2I 2I 2I 4B b I 8s")
packed_value = s.pack(*values)

# ----------------------------------------------------------------
# アンパックする
# ----------------------------------------------------------------
unpacked_value = s.unpack(packed_value)

# ----------------------------------------------------------------
# 表示
# ----------------------------------------------------------------
print("Format String :", s.format)
print("Original Value:", values)
print("Packed Value  :", packed_value)
print("0xPacked Value:", binascii.hexlify(packed_value))
print("Size          :", s.size)
print("Unpacked Value:", unpacked_value)


""" 実行結果
Format String : b'< 2I 2I 2I 4B b I 8s'
Original Value: [32, 64, 100, 200, 1, 1, 255, 0, 0, 255, 1, 0, b'palyer']
Packed Value  : b' \x00\x00\x00@\x00\x00\x00d\x00\x00\x00\xc8\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\xff\x00\x00\xff\x01\x00\x00\x00\x00palyer\x00\x00'
0xPacked Value: b'200000004000000064000000c80000000100000001000000ff0000ff010000000070616c7965720000'
Size          : 41
Unpacked Value: (32, 64, 100, 200, 1, 1, 255, 0, 0, 255, 1, 0, b'palyer\x00\x00')
"""
    

文字列をバイナリ化してファイル出力する

# coding: utf-8
# 文字列をバイナリ化してファイル出力する

import struct, binascii

# ----------------------------------------------------------------
# 文字列リスト
# ----------------------------------------------------------------
str_dict = {
            "good_morning"  : "おはよう",
            "good_afternoon": "こんにちは",
            "good_evening"  : "こんばんは",
            "good_night"    : "おやすみ"
            }
str_list = str_dict.values()

# ----------------------------------------------------------------
# パック
# ----------------------------------------------------------------
s = struct.Struct( " ".join( ["16s" for v in range(len(str_list))] ) )
packed_value = s.pack(*[ str.encode() for str in str_list ])

# ----------------------------------------------------------------
# バイナリファイルを出力
# ----------------------------------------------------------------
f = open("str_list.bin", "wb")
f.write(packed_value)
f.close()

# ----------------------------------------------------------------
# ヘッダーファイルを出力
# ----------------------------------------------------------------
f = open("str_list.def", "w")
f.write("""
// 文字列リストのID
""")
for i, key in enumerate(str_dict.keys()):
    f.write( "static const int ID_{name} = {value};\n".format(name=key.upper(), value=i) )
f.close()

# ----------------------------------------------------------------
# 出力したファイルからバイナリを読み込んでアンパックする
# ----------------------------------------------------------------
f = open("str_list.bin", "rb")
unpacked_value = s.unpack(f.read())
f.close()

# ----------------------------------------------------------------
# 表示
# ----------------------------------------------------------------
print("Format String :", s.format)
print("Original Value:", str_list)
print("Packed Value  :", packed_value)
print("0xPacked Value:", binascii.hexlify(packed_value))
print("Size          :", s.size, "bytes")
print("Unpacked Value:", [ b.decode() for b in unpacked_value ] )


""" 実行結果
Format String : b'16s 16s 16s 16s'
Original Value: dict_values(['おやすみ', 'こんにちは', 'こんばんは', 'おはよう'])
Packed Value  : b'\xe3\x81\x8a\xe3\x82\x84\xe3\x81\x99\xe3\x81\xbf\x00\x00\x00\x00\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x81\xaf\x00\xe3\x81\x93\xe3\x82\x93\xe3\x81\xb0\xe3\x82\x93\xe3\x81\xaf\x00\xe3\x81\x8a\xe3\x81\xaf\xe3\x82\x88\xe3\x81\x86\x00\x00\x00\x00'
0xPacked Value: b'e3818ae38284e38199e381bf00000000e38193e38293e381abe381a1e381af00e38193e38293e381b0e38293e381af00e3818ae381afe38288e3818600000000'
Size          : 64 bytes
Unpacked Value: ['おやすみ\x00\x00\x00\x00', 'こんにちは\x00', 'こんばんは\x00', 'おはよう\x00\x00\x00\x00']
"""
    

TRACK BACK URL

POST COMMENT

メールアドレスが公開されることはありません。

COMMENT