pythonでバイナリファイルを読み込む方法[open, readinto, ctypes]

python実装方法

Pythonを使ったバイナリファイルの読み方を紹介します。

この記事で学べる内容
  • Pythonでバイナリファイルを読み込む方法
  • フォーマットの決まったバイナリファイルを読み込む方法:ctypes.Structure

バイナリファイルを読み込む: open, read

バイナリファイルの読み込む場合は、テキストファイル同様にopen関数を使用し、モードを"rb"(read, binary)にします。

# 構文
# open("ファイルパス", "モード")
with open("./sample.bin", "rb") as f:
    f_sample =  f.read()

print(f_sample) # b'sample binary word.'

バイナリファイルを書き込みたい場合はモードを"wb"にし、テキストファイル同様にバイナリデータをwrite()で書き込めます。
(b"文字列"とすることでバイナリ型として書き込めます。)

with open("./sample.bin", "wb") as f:
    f.write(b"sample binary word.")

フォーマットの決まったバイナリファイルを読み込む

バイナリファイルはフォーマット仕様が提供され、その仕様に沿って読み込むことがあります。ここでは、ctypes.Structureライブラリを使って以下の図のフォーマットで記載されたバイナリファイルを、読み込んでいきます。

format
データフォーマット

データフォーマットを定義する

データフォーマットを定義するには、ctypes.Structureを継承したClassを作成します。
Classの中には、_fields_属性を作成し、フィールド名称とフィールド型をセットにしたタプルで記載していきます。
先ほどのデータフォーマットは以下のように記載されます。

import ctypes as c

# フォーマットを定義
class SampleFormat(c.Structure):
    _fields_ = [
        ("id", c.c_uint32), # 符号なし32ビット整数型
        ("type", c.c_char*4), # 4バイトの文字型
        ("data", c.c_char*120) # 120バイトの文字型
    ]

ctypesには様々なデータ型が定義されており、一覧は公式リファレンスから確認できます。

データフォーマットの定義ができたので、ファイルへの書き込みと読み込みを行ってみます。

バイナリファイルの読み書き

データフォーマットの内容をバイナリファイルへ書き込んでいきます。
書き込む値はデータフォーマットのインスタンス作成時に、初期値として指定できます。

# データフォーマットに値を代入
format_data = SampleFormat(100, b'DATA', 'バイナリのサンプルデータ。'.encode())

# バイナリファイルに書き込み
with open("./binary_format.bin", "bw") as f:
        f.write(format_data)

次に、バイナリファイルを読み込んでいきます。
読み込むまでの流れは次の2ステップになります。

  1. バイナリファイルを開く:open関数
  2. データフォーマットに代入:readintoメソッド

readintoメソッドを使うことで、事前に定義したフォーマットにバイナリデータを代入することができます。

with open("./format.bin", "rb") as f:
    # 定義したフォーマットのインスタンスを作成
    format_data = SampleFormat()
    # ファイルを読み込み、フォーマットに代入
    f.readinto(format_data) # 事前に要したバイナリデータの入れ物にデータを入れ込む

print(f'id: {format_data.id}') # 100
print(f'type: {format_data.type}') # b'DATA'
print(f'data: {format_data.data.decode()}') # バイナリのサンプルデータ。

書き込んだバイナリデータが読み込めていることが分かります。

ビッグエンディアン、リトルエンディアンの指定

バイトオーダー(ビッグエンディアン、リトルエンディアン)は、データフォーマットのClassを作成する際に、継承するClassを変更することで指定できます。

# ビッグエンディアンの場合
class BE_format(c.BigEndianStructure):
    _fields_ = [
        ("id", c.c_uint32),
        ("type", c.c_char*4),
        ("data", c.c_char*120)
    ]

# リトルエンディアンの場合
class BE_format(c.LittleEndianStructure):
    _fields_ = [
        ("id", c.c_uint32),
        ("type", c.c_char*4),
        ("data", c.c_char*120)
    ]

フォーマットのサイズを確認する

定義したデータフォーマットのサイズは、ctypes.Sizeofで確認できます。

print(c.sizeof(format_data)) # 128

参考サイト

PythonでバイナリをあつかうためのTips

コメント

タイトルとURLをコピーしました