たのしい工学

プログラミングを学んで、モノをつくりたいひと、効率的に仕事をしたい人のための硬派なブログになりました

【コンピュータサイエンスの独学】バイナリファイル

   

バイナリ・ファイルとは

int 型の 0x1234 を考えます。これをテキスト・ファイルとして格納するには数値を文字列化しなければなりません。その値を読み込んで元に戻すには文字列を数値化する必要があります。
これを内部形式そのままで書き込めばその手間はありません。読み出してもそのままの値で使用可能です。内部形式のデータは 0x00 から 0xFF まで使用するのでファイルはバイナリ形式です。変換に伴う手間も時間も必要無いので簡単便利で高速、良い事ずくめに思えますね。しかしそうではありません。

バイナリ・ファイルの環境依存性

C 言語では型の大きさを決めていません。型の中身のデータ構造についても各環境ごとに異なります。複数バイトのバイト単位の並びが下位から格納されるリトル・エンディアン形式やその逆のビッグ・エンディアン形式が存在します。ひょっとしたらその他の形式もあるかも知れません。構造体ではアラインメントやパディングが表面化しましたが、勿論環境によってこれらは異なります。
テキスト・ファイルは環境によって若干異なる事は説明しました。しかしバイナリ・ファイルは今説明した通り環境によって異なる要素がテキスト形式と比較して非常に多いのです。従ってバイナリ・ファイルは環境による互換性は無いと思った方が良いでしょう。
環境依存を極力少なくするのならテキスト形式、そうでなければバイナリ形式を用いるのが効率的です。

バイナリ・ファイルのアクセス

テキスト・ファイル同様順次アクセスが可能です。それに加えランダム・アクセスも出来ます。一般にファイルに対してランダム・アクセスと表現すると「指定キー位置のレコードをアクセスする」事を意味します。
国語辞典を例にします。「国語」との語を調べたければその読みである「こくご」の見出しを探します。その見出しを見付ければ意味が分かります。ここではファイルが国語辞典であり、一つのレコードは「見出し」と「意味」等で構成され、個別の見出しと意味等が各フィールドです。この場合は見出しが「キー」になります。これがキーによるランダム・アクセスであり一般的な手法です。
一方 C 言語にはその様な概念は無く「ファイルを読み書きする位置」が存在するだけです。もしキーによるランダム・アクセスを行いたければそのプログラムを作る必要があります。その代わりプログラム次第で柔軟なアクセスが行えます。よって C 言語によるランダム・アクセスはファイルの位置を任意に指定してデータを読み書きする事が基本です。テキスト・ファイルではこれが行えませんでしたがバイナリ・ファイルならバイト単位で指定出来ます。
ファイルの位置指定と聞くと難しく感じるかも知れません。ですが C 言語のランダム・アクセスは内部記憶装置のデータ・アクセスの延長です。ファイルの読み書き位置をポインターとして捉えてください。ポインターによるデータの読み書きと同じ感覚でファイルにアクセス出来ます。ポインター感覚なら配列やその他の基本となる型、構造体といったあらゆる型で読み書き可能です。簡単に思えて来たのならそれは正しいです。データのアクセスにストリーム関数を用いる一手間が必要なだけなのですから。

バイナリ・ファイルのランダム読み込み

これまでのファイルの読み取り方は、ファイルの先頭から最後まで順番に行われました。バイトを読み取るごとに、ファイルポインタは次の項目に進みました。これを繰り返して、出力したり入力したりしていました。

これまでのような、ファイルの先頭から順に読み取るファイル形式をシーケンシャルアクセスと呼びます。
単なるテキストデータの場合、これほど効率的な方法はありません。手間もかからず、理想的な読み取り方といえます。
しかし、バイナリデータの場合は適しているとは思え難いです。

バイナリファイルの場合、その仕様から多くの異なる目的のデータがバイトごとに並んでいることが多いでしょう。このデータをシーケンシャルにアクセスして、目的のデータだけをカットするのは大変手間がかかります。そこで、バイナリファイルの場合は任意の場所からアクセスできると非常に便利です。このような、特定の場所へのファイルアクセスをランダムアクセスと呼びます。

特定の位置にアクセスするには、ファイルポインタの位置を任意の場所に変更する必要があります。ランダムアクセスするためにはfseek()関数を使用します。

バイナリ・ファイルのランダム書き込み

読み書き共に任意の位置に対して行えるのがストリームをバイナリ・ファイルとして開いた時の特徴です。しかし書き込みをランダムに行うにはまだ書き込んでいない領域を飛ばして書き込めなければなりません。例を挙げると新規のファイルに対して最初に三番目を書き込み、次に先頭を書き込み、最後に二番目を書き込む、といった動作です。勿論可能で、その為に fseek 関数はファイルの最後より後ろへエラーにもならず移動出来るのです。

バイナリファイルのまとめ

バイナリ・ストリームに限らず、ストリームの読み書きはこれまでのプログラムを見て分かる様に定型処理です。ストリームを開き、ストリームに対してアクセス、不要になったらストリームを閉じる、これだけです。
ストリームの読み書きは現在の読み書き位置を基点に行われ、ストリームの起点を変更するのはポインター演算と大差ありません。
構造体型を連続してバイナリ・ファイルに書き込むと、そのファイルは構造体型の配列と同じと考えても構いませんし実際その様に操作可能でした。
バイナリ・ファイルはどんなファイル設計も可能ですが、その読み書き処理は全て自分でプログラムしなければなりません。
テキスト・ファイルは読み書きに制限は付きますがプログラムするのが易しく移植性は高めです。

ファイル処理を自由にこなすにはファイル構造やプログラムの設計法、そしてプログラムの基礎的な流れとその適用法を身に付けていなければなりません。ですからファイル処理プログラムを自由自在に組める様になって初めてプログラムの基礎が身に付いたといえるでしょう。

 - コンピュータサイエンス