バイナリファイル: 生のデータ

文字列変換なしの、純粋なデータ保存。画像もセーブデータもこれ。

テキストファイル
人間が読める文字だけで書かれたファイル。メモ帳で開ける。
バイナリファイル
画像や音声、プログラム本体など、バイト列がそのまま記録されたファイル。メモ帳で開くと文字化けする。
エンディアン
バイトの並び順。異なる機種間でバイナリデータを交換する際の障害になる。
冷凍食品 (Frozen Food)

バイナリファイルは「冷凍食品(生の食材)」です。 メモリにあるデータ(肉や魚)を、調理せずそのままの状態で保存(冷凍)します。解凍すれば、元の鮮度のまま(ビット列を変えずに)復元できます。 一方、テキストファイルは「調理済み料理」です。人間が食べやすいようにカットや味付け(改行コードの変換など)がされています。冷凍肉をいきなり調理済みとして扱おうとする(バイナリをテキストエディタで開く)と、変な味がしたり、お腹を壊したりします(文字化け)。

テキスト vs バイナリ

「テキストモード ("r")」でファイルを開くと、OSによっては改行コード(Windowsの \r\n など)が勝手に変換されます。これは文章を扱うには便利ですが、画像データなどの精密なデータを扱うとデータが壊れてしまいます。

「バイナリモード ("rb", "wb")」は、メモリ上のビット列を一切変更せずにそのまま読み書きします。int 型の数値を「文字列の "123"」ではなく「4バイトの数値データ」として保存できます。

構造体を丸ごと保存

<code>fwrite</code> を使うと、構造体のメモリ領域をそのままファイルにダンプできます。非常に高速で簡単です。

Write

fwrite
struct SaveData {
int hp;
int mp;
char name[20];
};
struct SaveData data = {100, 50, "Hero"};
// "wb" (Write Binary) モードで開く
FILE *fp = fopen("save.dat", "wb");
if (fp) {
// メモリの中身をそのままファイルに書き出す
fwrite(&data, sizeof(struct SaveData), 1, fp);
fclose(fp);
}

Read

fread
struct SaveData load_data;
// "rb" (Read Binary) モードで開く
FILE *fp = fopen("save.dat", "rb");
if (fp) {
// ファイルの中身をメモリに読み込む
fread(&load_data, sizeof(struct SaveData), 1, fp);
fclose(fp);
printf("Name: %s, HP: %d\n", load_data.name, load_data.hp);
}

実践テクニック

互換性の問題

バイナリ保存は便利ですが、「別のPC(Macで作ってWindowsで開くなど)」では読み込めないことがあります(エンディアンや型のサイズが違うため)。完全に安全にデータを交換するには、JSONなどのテキスト形式にするか、厳密なフォーマット定義が必要です。

演習課題

課題1: セーブデータ
HP, MP, Level を持つ構造体を定義し、プログラム終了時にファイルに保存、起動時にファイルから復元するプログラムを作ってください。

合格ライン

画像などを扱うときは "rb", "wb" を使う必要があると知っている
fwriteで構造体を保存できる