テキストファイルとバイナリファイルとは

ここではテキストファイルとかバイナリファイルと言ったときに、それがどんなデータをさすのか簡単に説明します。

ひとことでいうと、テキストファイルというのは、データを文字として扱っているということです。 一方、バイナリファイルというのはデータを文字としてみなしておらず、生のままデータを扱っているということになります。

#include <stdio.h>
#include <stdlib.h>

int main() {

  int i = 12345;
  FILE *fp = NULL;

  if ((fp = fopen("foo.txt", "w")) == NULL) {
    perror(NULL);
    return 1;
  }

  fprintf(fp, "%d", i);

  fclose(fp);
  return 0;
}

この結果作成されたファイルをテキストエディタで開いてみます。

すると、次のように表示されました。

12345

int 型の変数 i12345 という数字を代入して、 それを書き出したので、ファイルをみても 12345 とみえる。大変素直でわかりやすいですね。

実際にファイルに何が書きこまれたか、バイト列として確認してみましょう。

cat foo.txt | xxd
00000000: 3132 3334 35                             12345

cat コマンドはファイルの内容を標準出力に出力する Linux のコマンドで、 xxd コマンドは HEX データとして内容を出力します。上記のコマンドは cat コマンドの結果をパイプを通して、 xxd コマンドに渡したことになります。

プログラム内でははじめは整数の 12345 でしたが、 fprintf 関数を使って出力することにより、数字ではなく文字として出力されています。

バイナリデータとして出力する

それでは、int 型の変数 iをバイナリデータとして出力してみましょう。

#include <stdio.h>
#include <stdlib.h>

int main() {
  int i = 12345;
  FILE *fp = NULL;

  if ((fp = fopen("foo.txt", "wb")) == NULL) {
    perror(NULL);
    return 1;
  }

  fwrite(&i, sizeof(int), 1, fp);

  fclose(fp);
  return 0;
}

上と同じようにテキストエディタで開いてみます。

すると、次のように表示されました。

90

なぜか "90" とみえています。

実は 10 進数の数字 12345 は 16 進数で 3039 です。 0x30 に対応する ASCII コードは 00x399 です。

このため、12345 という数字をそのまま保存したら、たまたま文字として "90" が見えた、ということになります。

cat foo.txt | xxd
00000000: 3930 0000                                90..

09 ではなく 90 となるのは、バイトオーダーがリトルエンディアンだからです。 詳しくは「バイトオーダー」をみてください。

テキストファイルは基本的に、人が読んで直ちに理解可能なデータが格納されています。 わかりやすいとか、ポータブルなデータとしやすい代わり、一般的にデータサイズは大きくなります。

一方、バイナリーデータはデータサイズは小さくなるものの、人が読んでも通常意味が取れないので、 データレイアウトを厳密に定義しておく必要があります。