ユーニックス総合研究所

  • home
  • archives
  • python-read-binary-file

Pythonでバイナリファイルを読み込む

  • 作成日: 2021-04-19
  • 更新日: 2023-12-24
  • カテゴリ: Python

Pythonでバイナリファイルを読み込む

Pythonではファイルを開いてデータを読み込むという操作を行うことができます。
具体的には読み込むファイルはテキストファイルとバイナリファイルの2種類です。

バイナリファイルを読み込むには↓のようにコードを書きます。

with open('file.dat', 'rb') as fin:  
    data = fin.read()  

print(data)  

具体的に↑のコードについて解説していきます。

バイナリファイルとは何なのか?

ファイルとは、データの単位の1つです。
ファイルを使うとディスクにデータを書き込んだり、逆に読み込んだりが出来るようになります。

このファイルは大きく分けて2種類あります。
それは↓のような種類です。

  • テキストファイル
  • バイナリファイル

このうち、バイナリファイルはテキストファイルを内包します。
つまり大枠としてはバイナリファイルが基本となるファイルになるわけです。

バイナリファイルはバイト列の集まりのファイルです。
バイトはビットの集まりなので、バイナリファイルはビットの集まりと表現することも出来ます。
今のところ機械が理解できるデータは01の2種類、つまり電圧の高低ですが、この01を使ってデータを表現することを2進数(バイナリ)といいます。
01が並べられたモノがバイナリファイルで、これにフォーマットを付けたものがテキストファイルです。

open()でバイナリファイルを開く

↓のようなファイルを用意します。

1234  
abcd  

↑のファイルは「file.dat」として保存しておきます。
普通のエディタで作成していただいてOKです。

Pythonでファイルを開くにはopen()関数を使いますが、open()関数には開きたいファイルのファイル名と、そのファイルの開き方であるモードを指定する必要があります。
結論から言うとバイナリファイルを開きたい場合は、モードにはrbを指定します。
rbread binaryの頭文字だと思われます。

つまり↓のようなフォーマットでopen()を使います。

fin = open('file.dat', 'rb')  

finというのが開いたファイルオブジェクトです。finfile inputの略です。

ファイルは開いたら閉じないといけません。これは他の言語でも共通のルールかと思います。
理由は、リソースの解放という意味があります。
ファイルを閉じるにはファイルオブジェクトのclose()を使います。

fin = open('file.dat', 'rb')  
fin.close()  

このclose()を自動的にやってくれるのがwith文です。
with文でファイルを開けば、withのブロックが終了した時点で自動的にファイルが閉じられます。

with open('file.dat', 'rb') as fin:  
    pass  

バイナリファイルのファイルオブジェクトの詳細

バイナリファイルを開いた時のファイルオブジェクト(fin)の種類はtype()で確認することができます。
↓のように確認します。

with open('file.dat', 'rb') as fin:  
    print(type(fin))  

↑の結果は↓になります。

<class '_io.BufferedReader'>  

_io.BufferedReaderはモードrbで開いたときのファイルオブジェクトのタイプです。

このBufferedReaderのメソッドでよく使われるのはpeek()read()です。
これについては後述します。

BufferedReaderBufferedIOBaseIOBaseを継承したクラスです。
よってこの2つのクラスのメソッドを使うことができます。

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

モードrbで開いたバイナリファイルからデータを読み込むにはメソッドを使う必要があります。
データを読み込むメソッドには代表的なものにpeek()read()があります。
この2つについて解説します。

peek()でバイト列を読み込む

peek()read()の大きな違いは、read()が読み込んだ後に読み込み位置を進めるのに対して、peek()は読み込み位置を進めずに読み込みを行う点です。
ファイルから同じ内容のデータを何度も読み込みたい場合はpeek()が適していると言えます。

with open('file.dat', 'rb') as fin:  
    print(fin.peek())  
    print(fin.peek())  
    print(fin.peek())  

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

b'1234\nabcd'  
b'1234\nabcd'  
b'1234\nabcd'  

peek()の引数に読み込みたいサイズを渡すと読み込むサイズを指定することができるらしいですが、筆者の環境(Windows, Python3.9.2)では期待した結果は得られませんでした。
公式ドキュメントにも

返されるバイト数は、要求より少ないかもしれませんし、多いかもしれません。

とあるので、あまり指定には信頼性がないのかもしれません。

read()でバイト列を読み込む

read()は読み込みと同時に読み込み位置を進行させるメソッドです。
read()に引数を指定しない場合はread()EOFまたは読み込みがブロックされるまで読み込みます。

with open('file.dat', 'rb') as fin:  
    print(fin.read())  

↑の結果は↓になります。

b'1234\nabcd'  

read()の第1引数に読み込みたいバイト数を指定すると、そのバイト数だけ読み込んで読み込み位置を進めます。

with open('file.dat', 'rb') as fin:  
    print(fin.read(2))  # 2バイトだけ読み込む  
    print(fin.read(4))  # 4バイトだけ読み込む  
    print(fin.read())  # 全部読み込む  

↑の結果は↓になります。

b'12'  
b'34\na'  
b'bcd'  

読み込み位置をマニュアルで変更したい

ここでは範囲外になるので解説しませんが、読み込み位置をマニュアルで変更することをランダムアクセスファイルといいます。
これはファイルオブジェクトのseek()メソッドを使ってファイルの読み込み位置を変更する技術です。

おわりに

今回はバイナリファイルの読み込み方法を解説しました。
バイナリファイルを読み込めるようになれると、低レイヤ―な処理も書けるようになります。
ソケット通信などにも使える技術です。

🦝 < 目が`0`と`1`になる

🐭 < バイナリ目