銀月の符号

Python 使い見習いの日記・雑記

バイナリデータの読み込みのお供に struct モジュール

職場にてあるバイナリデータの中身を調べる際、身につけた&役に立ったのでメモ。例としてブログに上げるわけにはいかないから・・・とりあえず Python 2.5.2 の README.txt のみを収めた LZH 形式のアーカイブファイルのヘッダの始まり4要素分を例に。

http://homepage1.nifty.com/dangan/Content/Program/Java/jLHA/Notes/Notes.html の Level2 ヘッダ解説によると、最初の2バイトがヘッダの大きさ、続く5バイトが圧縮法の種類をあらわす文字列。続く4バイトが圧縮後ファイルサイズ、次の4バイトが圧縮前のファイルサイズを示す。バイトオーダーはリトルエンディアン。

struct モジュールでは読み書きするバイナリデータがどのような構成になっているかをフォーマット文字列で表す。 H で unsigned short 、5s で長さ5の char[] 、 L で unsigned long を表す。リトルエンディアンの指定は < をフォーマット文字列の先頭につけることでおこなう。また LLLLL のような繰り返しを 5L のように縮めて表すこともできる。詳しくは ライブラリリファレンスの struct 参照。

今回は2バイト、5バイト(文字列)、4バイト、4バイトを読みたいので、フォーマット文字列は <H5sLL もしくは <H5s2L となる。

バイナリデータを解読するには unpack 関数を、Python 基本型各種らをバイナリデータとしてまとめるには pack 関数を用いる。というわけで今回は unpack 関数を使用。

準備完了。さっそく読んでみることに。

>>> import struct
>>> readme = open('README.lzh', 'rb') # Python 2.5.2 の README を lh5 形式にて LHA 書庫に収めたもの
>>> raw_header = readme.read(2 + 5 + 4 + 4)
>>> header = struct.unpack('<H5s2L', raw_header)
>>> print header
(79, '-lh5-', 21239, 56354)

ヘッダ長が 79 バイト、圧縮形式が lh5 、圧縮後のサイズが 21,239 バイト、圧縮前のサイズは 56,354 バイトと読むことができた。