今さらPython3 (50) - バイナリファイル読み書き

第8章読んでます。

入門 Python 3

入門 Python 3

バイナリファイル書き込みと読み出し

>>> bdata = bytes(range(0,256))
>>> len(bdata)
256

まずは、バイナリデータを用意して、

>>> fout = open('bfile', 'wb')
>>> size = len(bdata)
>>> offset = 0
>>> chunk = 100
>>> while True:
...     if offset > size:
...         break
...     fout.write(bdata[offset:offset+chunk])
...     offset += chunk
... 
100
100
56
>>> 
>>> fout.close()
>>>

openのオプションに'wb'になっているのが違う。チャンク単位でかき込むのは1つの例であって、それ以外の方法でもいけるんだよね。

>>> fout = open('bfile', 'wb')
>>> fout.write(bdata)
256
>>> fout.close()
>>> 

全ぶっ込みでも問題なし。

>>> fin = open('bfile', 'rb')
>>> bdata = fin.read()
>>> len(bdata)
256
>>> fin.close()

これが読み出し。

クローズ忘れる

今回のお題を進めながらも、何回もclose()を忘れてたわけで。

>>> with open('relativity', 'wt') as fout:
...     fout.write(poem)
... 
150

with以下のコンテキストブロックが終わるとファイルを閉じてくれると理解。

8. Compound statements — Python 3.5.1 documentation

with構文の使い方は、ドキュメントのこのあたりを見るべし。正常に終わるか例外生成によって終わるとファイルを自動に閉じてくれる。ファイルが参照しなくなったときに自動でファイルが閉じられるとは言え、よく忘れるぐらいならwith構文を使うのを基本にした方が良いかも。

tell()からのseek()

>>> fin = open('bfile', 'rb')
>>> fin.tell()
0
>>> fin.seek(255)
255
>>> bdata2 = fin.read()
>>> len(bdata2)
1
>>> bdata2[0]
255
>>> 

tell()はファイルの先頭からの現在地までのオフセットをバイト単位で返す(なので上の例では0)、seek()で指定した場所に移動(255)して、そこから後ろをread()で読み込んでいる。実際には最後の1バイトを読み込まれたということになる。

>>> import os
>>> os.SEEK_SET
0
>>> os.SEEK_CUR
1
>>> os.SEEK_END
2

seek(offset, origin)の値(0,1,2)の説明に関して、0は先頭からoffsetバイトの位置に移動、1は現在位置からoffsetバイトの位置に移動、2は末尾からoffsetバイトの位置に移動。osモジュールで定義されているというのは、0,1,2の代わりに指定することが出来ると理解すれば良いのかな。

>>> fin = open('bfile', 'rb')
>>> fin.seek(-1,2)
255
>>> fin.tell()
255
>>> bdata = fin.read()
>>> len(bdata)
1
>>> bdata[0]
255
>>> 

fin.seek(-1,2)で、末尾から-1オフセットした場所に移動して、そこから末尾までを読み出していると。

>>> fin = open('bfile', 'rb')
>>> fin.seek(254,0)
254
>>> fin.tell()
254
>>> fin.seek(1,1)
255
>>> fin.tell()
255
>>> bdata = fin.read()
>>> len(bdata)
1
>>> bdata[0]
255
>>> 

こっちは、seek(1,1)を使っているパターン。最初に254オフセットして、その場所から1バイト移動なので(1,1)。ファイルの末尾まで読むというあたりは同じ。

(つづく)