【Python】バイナリファイルを読み書きモードで排他的に開く(モードx+b)【入門第69回】

202, 2019-09-28

目次

バイナリファイルを排他的に読み書きする

バイナリファイルを排他的に読み書きするにはopen関数のmode引数に文字列x+bを指定します。
このモードは開こうとするファイルが存在しない場合はファイルを新規作成して開きます。
開こうとするファイルがすでに存在する場合は例外FileExistsErrorを送出します。
このモードのopen関数から得られるファイルオブジェクトは_io.BufferedRandomです。

今回は具体的には下を見ていきます。

  • バイナリファイルを排他的に開く

  • io.BufferedRandomの詳細

  • バイナリファイルからデータを読み込む

  • バイナリファイルにデータを書き込む

ほかのファイル入出力についての入門記事は↓をご覧ください。

バイナリファイルを読み書きモードで排他的に開く

バイナリファイルを読み書きモードで排他的に開くにはopen関数を↓のようにして使います。

with open('alphas.dat', mode='x+b') as fp:
    pass

open関数の第1引数にファイルのパスを指定します。
mode引数には文字列x+bを指定します。

x+bモードのopen関数は開こうとするファイルが存在しない場合はファイルを新規作成してファイルを開きます。
そして、開こうとするファイルがすでに存在する場合は例外FileExistsErrorを送出します。
たとえば↓のようなコードで、alphas.datというファイルがすでに存在する場合、

try:
    with open('alphas.dat', mode='x+b') as fp:
        pass
except FileExistsError as e:
    print('ファイルが既に存在します。')
    print(e)

このコードの実行結果は↓のようになります。

ファイルが既に存在します。
[Errno 17] File exists: 'alphas.dat'

io.BufferedRandomの詳細

x+bモードのopen関数から得られるファイルオブジェクトは_io.BufferedRandomです。

with open('alphas.dat', mode='x+b') as fp:
    print(type(fp))

↑のコードの実行結果は↓のようになります。

<class '_io.BufferedRandom'>

_io.BufferedRandomの公式ドキュメントは↓です。

io.BufferedRandomio.BufferedReaderおよびio.BufferedWriterを継承したクラスです。

io.BufferedReaderおよびio.BufferedWriterはそれぞれio.BufferedIOBaseを、io.BufferedIOBaseio.IOBaseを継承しています。

これらのクラスの公式ドキュメントを参照すれば利用できるメソッドを一望することが出来ます。

バイナリファイルからデータを読み込む

x+bモードで開いたバイナリファイルのファイルオブジェクトからデータを読み込むにはreadメソッドを使います。

with open('alphas.dat', mode='x+b') as fp:
    data = fp.read()
    print(data)

↑のコードの実行結果は↓のようになります。

b''

x+bモードでファイルを開く場合、それはファイルを新規作成するときに限られます。
x+bモードはファイルがすでに存在する場合はエラーを出すからです。
そのため、↑のようなコードの結果は必ず空のバイト列になります。

バイナリファイルの読み込みについて詳しく知りたい方は↓の記事をご覧ください。

バイナリファイルにデータを書き込む

x+bモードで開いたバイナリファイルにデータを書き込む場合はファイルオブジェクトのwriteメソッドを使います。

with open('alphas.dat', mode='x+b') as fp:
    fp.write(b'abc')

↑のコードを実行するとalphas.datファイルの中身は↓のようになります。

abc

バイナリファイルの書き込みについて詳しく知りたい方は↓の記事をご覧ください。

データを書き込んでから読み込む

いったんファイルにデータを書き込んで、そのデータを読み込みたい場合は↓のようにします。

import os

with open('alphas.dat', mode='x+b') as fp:
    # データを書き込む
    fp.write(b'abc')

    # ファイルのオフセット位置をファイル先頭に移動する
    fp.seek(0, os.SEEK_SET)

    # データをファイル先頭から読み込む
    data = fp.read()
    print(data)

↑のコードの実行結果は↓のようになります。

b'abc'

ファイルオブジェクトは内部にファイルのオフセット位置を持っています。
ファイルオブジェクトはこのオフセット位置を基準にしてファイルを読み書きします。
このオフセット位置はwriteメソッドやreadメソッドを使うと自動でファイル末尾に向かって進みます。
そのため、↑の例ではwriteメソッドを読んだ後にファイルのオフセット位置をファイルの先頭に戻しています。
そうすることでreadではファイルの先頭からデータを読み込むことが出来るようになります。

seekメソッドは第1引数に基点からの相対位置、第2引数に基点位置を指定します。
os.SEEK_SETはファイル先頭を表す定数です。
そのためseek(0, os.SEEK_SET)は「ファイル先頭から0の位置にオフセット位置を移動する」という意味になります。
つまり、ファイル先頭にオフセット位置を移動してるわけです。

ランダムアクセスについて詳しく知りたい方は↓の記事をご覧ください。

おわりに

x+bモードはファイルを排他的に開くため、w+bモードと違い既存のファイルを破壊しません。
うまいことw+bモードと使い分けましょう。

また見てね

関連動画





スポンサーリンク

スポンサーリンク

スポンサーリンク

スポンサーリンク