しんで覚えるC言語
しんで覚えるC言語

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

テキストとバイナリ
ファイルにはさまざまな種類のものがありますが、もっとも基本的な区別として、
テキストかバイナリかという違いがあります。

すべてのファイルは本質的にはバイナリファイルです。
バイナリを直訳すると、2進数という意味なのですが、
バイナリファイルとはその名の通り、2進数で記録されたファイル、
要するに、数値のみで記録されたファイルのことを意味します。

それに対して、テキストファイルは、文字列だけが記録されたファイルです。
コンピュータの中では、文字列といえども数値で表されているので、
テキストファイルも、本質的にはバイナリファイルです。
しかし、テキストファイルは文字列で記録されているため、
テキストエディタなどで修正を行うことが容易です。

バイナリファイルも、特定のエディタで閲覧・修正できますが、
すべてのデータが数値の固まりになっているため、
中身を見ても、その意味がまったくわかりません。
しかし、数値を直接書き込むため、サイズが少なく高速です。

一般に、取り扱いを容易にする必要がある場合はテキストファイル、
高速性が必要とされる場合にはバイナリファイルを利用することが多いようです
ファイルの開閉
テキストであれ、バイナリであれ、ファイル操作の基本的な手順に変わりはありません。
バイナリファイルも、fopen関数、fclose関数を使って開閉します。
ファイル名、モードの指定方法もまったく同じです。
ただし、バイナリファイルを開く時には、モード文字列の最後にbをつけます

ここまで説明したことがわかれば、バイナリファイルの開閉ができます。
次のプログラムは、test.datと言う名前のファイルを書き込みのために開く例です。

ソースコード
#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("test.dat", "wb");
    fclose(file);
    return 0;
}

このプログラムを実行すると、test.datという名前のファイルが作成されます。
今回は開いただけなので、当然中身は空っぽです。

混同しても使える
実際には、バイナリで開いてもテキストデータを読み書きできますし、
逆も可能ですが、改行の扱いなどで不便な点が多くなります。

ファイルへの書き込み
ファイルに数値を直接書き込むには、fwrite関数を使用します。
fwrite関数の使い方は、次の通りです。

fwrite関数
fwrite(書き込む変数アドレス, 1項目のサイズ, 項目数, ファイルポインタ);

書き込む数値を変数に代入しておき、その変数のアドレスを指定します。
項目のサイズはsizeof演算子を使用して求めることができます。
変数を書き込むだけなら、項目数はとりあえず1で構いません。
次のプログラムは、test.datファイルに 100という数値を書き込みます。

ソースコード
#include <stdio.h>

int main(void)
{
    int buf = 100;
    FILE *file;
    file = fopen("test.dat", "wb");
    fwrite(&buf, sizeof(buf), 1, file);
    fclose(file);
    return 0;
}

このプログラムを実行すると、test.datファイルに値が書き込まれますが、
この値は、一般的なテキストエディタで見ることはできません。
バイナリファイルを見るには、バイナリエディタが必要になります。
下記は筆者が愛用しているエディタです。

hgBed http://www.vector.co.jp/soft/win95/util/se081906.html

バイナリエディタを使用してファイルを開くと、次のようになります。
現代のコンパイラではint型は32ビットなので、8バイトで書き込まれます。

バイナリエディタで開いた「test.dat」
64 00 00 00

バイナリエディタでは、数値を16進数で表示します。
その為、100という数値は、64と表示されます。

リトルエンディアンとビッグエンディアン
数学では、100を16進数に変換すると、0064になります。
しかし、バイナリエディタで閲覧した結果では、6400になっています。
これは、インテル互換CPUの特徴で、リトルエンディアンと呼ばれる表現です。
この表現では、16進数を2桁ずつに区切り逆の順番で保存します。

一方、16進数の順番通りに表現する方式を採用するCPUもあります。
こちらはビッグエンディアンと呼ばれます。

リトルエンディアンはわかりにくく見えますが、
先頭に意味がある数値が来やすいという利点があり、データ読み取り上有利なため、
現代ではリトルエンディアンが主流となっています。

fwrite関数による書き込みでは、配列を1度で書き込むこともできます。
やり方は、変数の代わりに配列を指定するだけです。
次のプログラムは、配列の値を書き込むプログラムです。

覚えていますか
配列名は、式の中では先頭アドレスになるので、&をつけません。


ソースコード
#include <stdio.h>

int main(void)
{
    int buf[] = {10, 100, 1000, 10000};
    FILE *file;
    file = fopen("test.dat", "wb");
    fwrite(buf, sizeof(buf), 1, file);
    fclose(file);
    return 0;
}

このプログラムを実行すると、test.datに値が書き込まれます。
バイナリエディタを使用してファイルを開くと、次のようになります。

バイナリエディタで開いた「test.dat」
0A 00 00 00 64 00 00 00 E8 03 00 00 10 27 00 00

ファイルからの読み込み
ファイルの数値を直接読み込むには、fread関数を使用します。
fread関数の使い方は、次の通りです。

fread関数
fread(読み込む変数のポインタ, 1項目のサイズ, 項目数, ファイルポインタ);

これを見ると、使い方はfwrite関数と同じであることがわかります。
次のプログラムは、test.datファイルから、int型の数値を読み込みます。

ソースコード
#include <stdio.h>

int main(void)
{
    int buf;
    FILE *file;

    file = fopen("test.dat", "rb");
    fread(&buf, sizeof(buf), 1, file);
    fclose(file);

    printf("%d\n", buf);

    return 0;
}

このプログラムの実行結果は、test.datファイルの内容によって変わりますが、
第3項で作成したプログラムによって書き込まれていた場合、次の通りになります。
test.datファイルの中身が次の通りだった場合、実行結果は次の通りになります。

バイナリエディタ「test.dat」をこのようにする
0A 00 00 00


実行結果
10

fwrite関数と同様にして、配列を読み込むこともできます。

バイナリファイルとテキストファイルの使い分け
バイナリファイルの利点は、読み書きが高速で、ファイルサイズが少なくなることです。
したがって、画像、動画、音、など、なるべく高速に扱いたいファイルは、基本的にバイナリファイルです。

それに対して、テキストファイルの利点は、人間が編集しやすいことです。
困ったときには、テキストファイルにしておけば、なにかと扱いやすくて重宝します。



本サイトについて

苦しんで覚えるC言語(苦C)は
C言語入門サイトの決定版です。
C言語の基本機能を体系立てて解説しており、
市販書籍と同等以上の完成度です。

第0部:プログラム概要編
  1. プログラムとは何か?
2章:プログラムの書き方
  1. 書き方のルール
  2. 書き方の慣習
  3. 練習問題2
3章:画面への表示
  1. 文字列の表示
  2. 改行文字
  3. 練習問題3
6章:キーボードからの入力
  1. 入力用の関数
  2. 入力の恐怖
  3. 練習問題6
9章:回数が決まっている繰り返し
  1. 繰り返しを行う文
  2. ループ動作の仕組み
  3. 練習問題9
10章:回数がわからない繰り返し
  1. 回数不明ループ
  2. 入力チェック
  3. 練習問題10
13章:複数の変数を一括して扱う
  1. 複数の変数をまとめて扱う
  2. 配列の使い方
  3. 練習問題13
20章:複数のソースファイル
  1. 最小限の分割
  2. 分割の定石
  3. 練習問題20
コメントシステムを読込中・・・