カネキン伊藤テック

Msgpack

MessagePack形式はプログラミング言語と独立したデータ構造のバイナリ表現のためのフォーマットで、「JSONのバイナリ版」と考えるとわかりやすい。MessagePack形式へのシリアライズや、シリアライズされたMessagePack形式のバイト列からのデシリアライズがJSONなどと比較して高速に行え、またシリアライズしたときの容量も小さいことから筆者は大量のデータを dict などの構造のままダンプするときなどに活用している。

PythonでMessagePack形式を扱うには python-msgpack でパッケージをインストールして利用するのが一般的だろう。 pip install python-msgpack でインストールできる。

データ構造をMessagePack形式にエンコードする(packする)

msgpack.packb() を使うことでMessagePack形式にエンコードされたバイト列を得ることができる。

import msgpack

a = dict(
	a=1,
	b="abc",
	c=False,
	d=None,
	e=[1,2,3],
	f={"x": 123, "y": 456, "z": "aiueo"},
	g=b'binary string'
)

packed = msgpack.packb(a)  # bytes型

データ構造をMessagePack形式にしてファイルに書き込む

msgpack.packb() した内容をバイナリモードでオープンしたファイルに書き込めばOK

import msgpack

a = dict(a=123, b="abc", c=[1,2,3], d={"x": 123, "y": "yyy"})
packed = msgpack.packb(a)

out_f = "./out.mp"
with open(out_f, "wb") as fh:
	# msgpackはバイナリ形式なのでwbモードでオープン
	fh.write(packed)

MessagePack形式のバイト列をデコード(unpack)してPythonのデータ構造にする

msgpack.unpackb() でデコードできる。

import msgpack


# dict(a=123, b="abc", c=[1,2,3], d={"x": 123, "y": "yyy"}) 
# をmsgpack.packb()したもの
packed = b'\x84\xa1a{\xa1b\xa3abc\xa1c\x93\x01\x02\x03\xa1d\x82\xa1x{\xa1y\xa3yyy'

unpacked = msgpack.unpackb(packed)

MessagePack形式データが書き込まれたファイルを読み込んでPythonのデータ構造にする

バイナリ+読み込みモードでオープンしたファイルからバイナリデータを読み込んで msgpack.unpackb() でデコードする。

import msgpack

f = "./data.mp"
with open(f, "rb") as fh:
	# msgpack形式のデータを読み込む(bytes型)
	packed = fh.read()

	# Pythonの構造体にunapck
	unpacked = msgpack.unpackb(packed)

MessagePackストリーム形式のファイルを作る

MessagePack形式のオブジェクトを続けて書き込むと、後述の Unpacker でストリームとしてiterableに読み込んで処理できるなど都合がよい。JSON-Lines形式の置き換えなどとしておすすめ。

import msgpack

items = [
	{"name": "alice", "age": 23},
	{"name": "bob", "age": 24},
	{"name": "charlie", "age": 25}
]

f = "./stream.mp"
with open(f, "wb") as fh:
	for item in items:
		fh.write(msgpack.packb(item))

MessagePackストリーム形式のファイルからデータをイテレーションしながら読み込む

MessagePackストリームを for 文などでイテレートして読み込むには msgpack.Unpacker クラスを使うとよい。

import msgpack

f = "./stream.mp"

with open(f, "rb") as fh:
	unpacker = msgpack.Unpacker(fh)

	for item in unpakcer:
		print(item)

参考リンク