【Python】バイナリファイルを読み書きする
Pythonでバイナリファイルを読み書きする必要が生じたので、そのためのメモです。
ファイルのオープン・クローズ
ファイルをオープンするにはopen()
をつかいます。この時バイナリファイルであることを示すため、"rb"
はたは"wb"
, "ab"
, "xb"
を指定します。一方、クローズするにはclose()
を使います。
f = open("test.dat", "wb")
f.close()
"rb"
等の違いは以下のようになります。
オプション | 意味 |
---|---|
"rb" | 読み込み |
"wb" | 書き込み |
"ab" | 書き込み+ファイルの末尾に移動 |
"xb" | ファイルが存在しない時に書き込み。存在する場合はエラー |
読み書きの操作が連続し、操作が終了したらファイルをクローズするような場合はwith
構文を使うと便利です。ブロックが終了すると自動的にファイルがクローズされます。
with open("test.dat", "rb") as f:
a = f.read()
ランダムアクセス
現在位置を返す
ファイルの現在位置を返すにはtell()
を使います。
# fはファイルオブジェクト
pos = f.tell()
ポインタの移動
ファイルのポインタを移動するにはseek()
を使います。seek()
にはファイルのどこを基準とするかを示すオプションが設定できます。値はos
モジュールで定義されています。省略するとos.SEEK_SET
が指定されます。
値 | 基準となる位置 | 指定する値 |
---|---|---|
os.SEEK_SET | ファイルの先頭 | 正 |
os.SEEK_CUR | 現在のポインタ | 正または負 |
os.SEEK_END | ファイルの終わり | 負 |
# osモジュールをインポートする
import os
# fはファイルオブジェクト
f.seek( 5, os.SEEK_SET) # 先頭から5バイト目
f.seek(-3, os.SEEK_CUR) # 現在位置から3バイト前
f.seek(-5, os.SEEK_END) # ファイル終端から5バイト前
読み書き
ファイルへのバイト列の読み込みにはread()
を、書き込みにはwrite()
を使います。文字列や数値を読み書きするには、バイト列を経由する必要があり、変換が必要です。
# fはファイルオブジェクト
b = f.read(32) # 32バイト読み込み
b = b'123'
f.write(b) # バイト列書き込み
文字列
文字列とバイト列の変換には、decode()
やencode()
を使います。また、後述するstruct
モジュールも使用できます。
# fはファイルオブジェクト
b = f.read(10)
str = b.decode() # バイト列を文字列に変換
str = "12345"
b = str.encode() # 文字列をバイト列に変換
f.write(b)
数値の読み書き
整数の読み書き
整数とバイト列の変換には、int.from_byte()
やto_bytes()
を使います。また、後述するstruct
モジュールも使用できます。
# byteorderを使うために必要
from sys import byteorder
# fはファイルオブジェクト
b = f.read(4)
val = int.from_bytes(b, byteorder) # 4バイトのバイト列を整数に変換
val = 12345
b = val.to_bytes(4, byteorder) # 整数を4バイトのバイト列に変換
f.write(b)
浮動小数点数の読み書き
浮動小数点数とバイト列の変換にはstruct
モジュールを使用します。unpack()
の戻り値はタプルなので、受け取り方に注意が必要です。
# structモジュールを使うために必要
from struct import unpack, pack
# fはファイルオブジェクト
b = f.read(8)
val, = unpack('d', b) # 8バイトのバイト列を浮動小数点数に変換
val = 12.345
b = pack('f', val) # 浮動小数点数を4バイトのバイト列に変換
f.write(b)
unpack()
およびpack()
で指定可能な書式指定文字には、以下のものがあります。
記号 | 意味 |
---|---|
'f' | 単精度浮動小数点数(4バイト) |
'd' | 倍精度浮動小数点数(8バイト) |
'q' | 符号付き整数(8バイト) |
'Q' | 符号なし整数(8バイト) |
'i' , 'l' | 符号付き整数(4バイト) |
'I' , 'L' | 符号なし整数(4バイト) |
'h' | 符号付き整数(2バイト) |
'H' | 符号なし整数(2バイト) |
'c' | 文字(1バイトのバイト列) |
'b' | 符号付き整数(1バイト) |
'B' | 符号なし整数(1バイト) |
's' , 'p' | 固定長バイト列(10s などのように長さと一緒に指定) |
複数のデータの読み書き
複数のデータを纏めて読み書きするには、struct
モジュールを使用します。
# structモジュールを使うために必要
from struct import unpack, pack, calcsize
format = "15sl10s"
size = calcsize(format) # フォーマットからバッファのサイズを計算する
b = f.read(size)
s1, val, s2 = unpack(format, b)
s1 = s1.strip(b'\0x00').decode() # ヌル文字を取り除く
s2 = s2.strip(b'\0x00').decode() # ヌル文字を取り除く
s1 = "テスト"
val = 123
s2 = "abcdefghij"
b = pack(format, s1.encode(), val, s2.encode())
f.write(b)
以上、Pythonでのバイナリファイルの読み書き方法についてまとめてみました。
ディスカッション
コメント一覧
まだ、コメントがありません