Skip to content

7.2 バイナリデータ

テキストデータでは難しい操作も、バイナリデータとして扱うことで効率よく行えることがあります。ファイル形式の解析やネットワークパケットの処理などを行うためには、Pythonでのバイナリデータ処理の基礎を知っておく必要があります。

7.2.1 バイトとバイト列 (bytesbytearray)

Section titled “7.2.1 バイトとバイト列 (bytes と bytearray)”

Python 3には、0から255までの値を取る8ビット整数のシーケンス(データの並び)として、以下の2種類が用意されています。

  • bytes: イミュータブル(変更不可)。バイトのタプルのようなものです。
  • bytearray: ミュータブル(変更可能)。バイトのリストのようなものです。
blist = [1, 2, 3, 255]
# bytesの作成(イミュータブル)
the_bytes = bytes(blist)
print(the_bytes) # b'\x01\x02\x03\xff'
# bytearrayの作成(ミュータブル)
the_byte_array = bytearray(blist)
print(the_byte_array) # bytearray(b'\x01\x02\x03\xff')

b'...' という表記は bytes 値を表します。Pythonは表示の際、有効なASCII文字に該当するバイトはそのまま文字として表示し、それ以外は \x に続く16進数で表示します。

7.2.2 struct によるバイナリデータの変換

Section titled “7.2.2 struct によるバイナリデータの変換”

標準ライブラリの struct モジュールを使うと、CやC++の構造体のようなバイナリデータと、Pythonのデータ構造を相互に変換できます。

  • unpack(): バイナリデータをPythonのデータ(タプル)に変換(抽出)します。
  • pack(): Pythonのデータをバイナリデータに変換します。

例として、PNGファイルのバイナリデータの一部から、画像の幅と高さを抽出してみます。

import struct
# PNGファイルの先頭24バイトのデータ(ダミーデータ)
data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x9a\x00\x00\x00\x8d'
# 16番目から24番目のバイトを抽出
# '>LL' は「ビッグエンディアン(>)」の「符号なし長整数(L)が2つ」という意味
width, height = struct.unpack('>LL', data[16:24])
print('width:', width, 'height:', height)
# 出力: width: 154 height: 141
# 逆に、Pythonのデータをバイト列に変換する
print(struct.pack('>L', 154))
# 出力: b'\x00\x00\x00\x9a'

7.2.4 binascii によるバイト/文字列の変換

Section titled “7.2.4 binascii によるバイト/文字列の変換”

binascii モジュールは、バイナリデータと16進文字列表現などを相互変換する際に便利です。Pythonのデフォルトの \x 混じりの表示ではなく、純粋な16進数の文字列として扱いたい場合に使用します。

import binascii
valid_png_header = b'\x89PNG\r\n\x1a\n'
# バイト列を16進数の文字列に変換
hex_str = binascii.hexlify(valid_png_header)
print(hex_str)
# 出力: b'89504e470d0a1a0a'
# 16進数の文字列をバイト列に戻す
print(binascii.unhexlify(hex_str))
# 出力: b'\x89PNG\r\n\x1a\n'

Pythonは、C言語とよく似たビットレベルの演算子を提供しています。これらは数値を2進数のビット列として操作します。

演算子意味例 (a=5(0b0101), b=1(0b0001))結果
&AND(論理積)a & b1 (0b0001)
``OR(論理和)`a
^排他的OR(XOR)a ^ b4 (0b0100)
~ビット反転(NOT)~a-6 (符号も反転する)
<<左シフトa << 110 (0b1010、2倍になる)
>>右シフトa >> 12 (0b0010、1/2になる)