検索
連載

[解決!Python]バイナリファイルの読み書きまとめ解決!Python

バイナリファイルに対して文字列と整数を読み書きする方法、struct/pickle/shelveモジュールを使ってバイナリファイルに各種データを読み書きする方法を1ページにまとめて紹介。

PC用表示 関連情報
Share
Tweet
LINE
Hatena
「解決!Python」のインデックス

連載目次

 ここでは本連載でこれまでに紹介してきたバイナリファイルの読み書きの方法をまとめる。詳しい解説はコード例の後で紹介しているリンクを参照してほしい。テキストファイルの読み書きについては「テキストファイルの読み書きまとめ」を参照されたい。

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

# 文字列のバイナリファイルへの書き込み
with open('test.bin', 'wb') as f:
    s = 'ディープインサイダー'
    b = s.encode()  # 文字列もバイト列にエンコードする必要がある
    f.write(b)  # バイナリファイルにはバイト列しか渡せない

# 文字列のバイナリファイルからの読み込み
with open('test.bin', 'rb') as f:
    b = f.read()
    s = b.decode()

print(s)  # ディープインサイダー

# 整数のバイナリファイルへの書き込みと読み込み
from sys import byteorder

print(byteorder)  # littleもしくはbig
length = 4  # 4バイト長整数に変換する

with open('test.bin', 'wb') as f:
    n = 123456
    b = n.to_bytes(length, byteorder)  # nを4バイト長の符号なし整数に変換
    f.write(b)

# 整数のバイナリファイルからの読み込み
with open('test.bin', 'rb') as f:
    b = f.read(length)  # lengthだけバイナリファイルから読み込み
    n = int.from_bytes(b, byteorder)  # バイト列を整数に変換する

print(f'read data: {n}'# read data: 123456

# 整数リストのバイナリファイルへの書き込みと読み込み
nlist = [1, 2, 3, 4, 5, 6]
length = 4  # 4バイト長整数

with open('test.bin', 'wb') as f:
    # 整数リストをバイト列リストに変換してファイルに書き込み
    blist = [n.to_bytes(length, byteorder) for n in nlist]
    f.writelines(blist)
    # 整数リストをバイト列に変換してファイルに書き込み
    #b = b''.join([n.to_bytes(length, byteorder) for n in nlist])
    #f.write(b)

# バイナリファイルからの整数の連続読み込み
with open('test.bin', 'rb') as f:
    result = []
    b = f.read(length)  # lengthだけバイナリファイルから読み込み
    while b:  # データがあるだけ以下を繰り返す
        n = int.from_bytes(b, byteorder)  # 読み込んだデータを整数に変換
        result.append(n)  # リストに追加
        b = f.read(length)  # lengthだけバイナリファイルから読み込み

print(result)  # [1, 2, 3, 4, 5, 6]

# バイト列を読み込んだ後にmemoryviewオブジェクトを得て、型変換を行う
with open('test.bin', 'rb') as f:
    b = f.read()

mv = memoryview(b)
result = mv.cast('i').tolist()
print(result)  # [1, 2, 3, 4, 5, 6]


 バイナリファイルに対する読み書きについては「バイナリファイルを読み書きするには:文字列と整数編」を参照のこと。

structモジュールを使ったバイナリファイルの読み書き

# structモジュールを使ってバイナリファイルに書き込み
from struct import pack, unpack, calcsize, iter_unpack

person = ('かわさき', 120, 99.9)
fmt = '20sid'  # 長さ20のバイト列(20s)、整数(i)、倍精度浮動小数点(d)
b = pack(fmt, person[0].encode(), person[1], person[2])  # fmtに従ってバイト列化

with open('data.bin', 'wb') as f:
    f.write(b)

# データサイズの計算
data_size = calcsize(fmt)
print(data_size)  # 32(このデータは32バイト長)

# バイナリファイルから読み込んで、structモジュールを使って復元
with open('data.bin', 'rb') as f:
    b = f.read(data_size)

data = unpack(fmt, b)
data = (data[0].strip(b'\x00').decode(), data[1], data[2])
print(data)  # ('かわさき', 120, 99.9)

# pathlibモジュールを使う
from pathlib import Path
p = Path('data2.bin')
b = pack(fmt, person[0].encode(), person[1], person[2])
p.write_bytes(b)

b = p.read_bytes()
data = unpack(fmt, b)
data = (data[0].strip(b'\x00').decode(), data[1], data[2])
print(data)  # ('かわさき', 120, 99.9)

# 複数のデータをバイナリファイルに書き込み
p_list = [('かわさき', 120, 99.9),
          ('えんどう', 60, 68.3),
          ('いっしき', 25, 65.2)]

fmt = '20sid'
with open('data.bin', 'wb') as f:
    b = [pack(fmt, p[0].encode(), p[1], p[2]) for p in p_list]
    f.writelines(b)

# 複数のデータをバイナリファイルから読み込み
data_size = calcsize(fmt)

with open('data.bin', 'rb') as f:
    b = f.read()

result = [(d[0].strip(b'\x00').decode(), d[1], d[2]) for d in iter_unpack(fmt, b)]

print(result)


書式指定文字 Pythonのデータ型 Cのデータ型 サイズ
x パディング
c 長さ1のバイト列 char 1
b 整数 signed char 1
B 整数 unsigned char 1
i 整数 int 4
I 整数 unsigned int 4
f 浮動小数点数 float 4
d 浮動小数点数 double 8
s、p 文字列をバイト列に変換したもの char[]
structモジュールで使われる書式指定文字(抜粋)

 structモジュールを使ったバイナリファイルの読み書きについては「バイナリファイルを読み書きするには:structモジュール編」を参照のこと。

pickleモジュールを使ったバイナリファイルの読み書き

import pickle

favs = ['beer', 'sake']
mydata = {'name': 'かわさき', 'age': 999, 'weight': 123.4, 'favs': favs}

# pickle化してファイルに書き込み
with open('pickled.pkl', 'wb') as f:
    pickle.dump(mydata, f)

# 非pickle化
with open('pickled.pkl', 'rb') as f:
    mydata2 = pickle.load(f)
    favs2 = mydata2['favs']

print(mydata2)
# 出力結果
# {'name': 'かわさき', 'age': 999, 'weight': 123.4, 'favs': ['beer', 'sake']}

print(f'mydata2 == mydata: {mydata2 == mydata}'# mydata2 == mydata: True
print(f'mydata2 is mydata: {mydata2 is mydata}'# mydata2 is mydata: False

# クラスのインスタンスのpickle化
class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age

foo = Foo('かわさき', 999)

with open('pickled.pkl', 'wb') as f:
    pickle.dump(foo, f)

# クラスのインスタンスの非pickle化
del foo  # インスタンスを削除
with open('pickled.pkl', 'rb') as f:
    foo = pickle.load(f)  # 復元

print(f'name: {foo.name}, age: {foo.age}') # name: かわさき, age: 999

# 関数オブジェクトとクラスオブジェクトのpickle化
def hello():
    print('hello')

with open('pickled.pkl', 'wb') as f:
    pickle.dump(Foo, f)  # 一つのファイルに複数のオブジェクトをpickle化できる
    pickle.dump(hello, f)

with open('pickled.pkl', 'rb') as f:
    Bar = pickle.load(f)  # FooクラスをBarクラスに復元
    greet = pickle.load(f)  # hello関数をgreet関数に復元

bar = Bar('bar', 101)
print(f'name: {bar.name}, age: {bar.age}'# name: bar, age: 101
greet()  # hello

# Fooインスタンスの復元にはFooクラスが定義されている必要がある
foo = Foo('かわさき', 999)
with open('pickled.pkl', 'wb') as f:
    pickle.dump(foo, f)

del Foo, foo  # Fooクラスとそのインスタンスであるfooを削除
with open('pickled.pkl', 'rb') as f:
    foo = pickle.load(f)  # FooクラスがないのでAttributeError例外

class Foo# 上とは別のFooクラスを定義してみる
    def __init__(self, a, b):
        self.a = a
        self.b = b

with open('pickled.pkl', 'rb') as f:
    foo = pickle.load(f)  # 復元できてしまう

print(foo.a)  # AttributeError例外(復元したfooにはa属性はない)


 pickleモジュールを使ったバイナリファイルの読み書きについては「バイナリファイルを読み書きするには:pickle編」を参照のこと。

shelveモジュールを使ったバイナリファイルの読み書き

import shelve

data_file = 'mydata'
key = 'person_data'

person_data = [('kawasaki', 120), ('isshiki', 38)]

with shelve.open(data_file) as d:
    d[key] = person_data

with shelve.open(data_file) as d:
    data = d[key]

print(data)  # [('kawasaki', 120), ('isshiki', 38)]

# デフォルトでは読み書き両用でオープンされる
num_data = [1, 2, 3, 4, 5]

with shelve.open(data_file) as d:
    data = d[key]  # 読み込み
    print(data)  # [('kawasaki', 120), ('isshiki', 38)]
    d['num_data'] = num_data  # 書き込み
    nums = d['num_data'# 読み込み
    print(nums)  # [1, 2, 3, 4, 5]

# writeback=False
more_data = ('endo', 45)

with shelve.open(data_file) as d:
    data = d[key]
    data.append(more_data)  # 読み出したデータに追加
    print(d[key])  # [('kawasaki', 120), ('isshiki', 38)]
    d[key] = data  # 反映するには元のキーの値を置き換える必要がある
    print(d[key])  # [('kawasaki', 120), ('isshiki', 38), ('endo', 45)]

# writeback=True
one_more_data = ('shimada', 50)

with shelve.open(data_file, writeback=True) as d:
    data = d[key]
    data.append(one_more_data)  # Shelfオブジェクトへの操作はキャッシュされる
    print(d[key])  # [('kawasaki', 120), ('isshiki', 38), ('endo', 45), ('shimada', 50)]
    # closeメソッドかsyncメソッドの呼び出しで、キャッシュの内容が書き込まれる。
    # キャッシュサイズが大きくなると書き戻しに時間がかかる点には注意


 shelveモジュールを使ったバイナリファイルの読み書きについては「バイナリファイルを読み書きするには:shelve編」を参照のこと。

「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

[an error occurred while processing this directive]
ページトップに戻る