ファイル入出力

たいていのプログラムでは、起動したらなんらかのデータを読み込む。 そしてデータを処理した結果を書き出す。 プログラムによっては、毎回必ず同じデータを読むことがある。たとえば 商品と値段表や、学籍番号と名前、などのように一度決まったら しばらく同じものを使うような性質のデータを処理する場合である。 そのような場合は、決まったデータをファイルに保存しておいて、 プログラムが勝手にそのファイルを開いてデータを読み込むようにしておくと 都合が良い。

データの読み込みや書き出しを特定のファイルに対して行なうための 関数が fopen/fclose である。

ファイルの読み込み

ファイルから、データを読むためには以下の手順を取る。

  1. ファイル構造体のポインタ変数を宣言
  2. fopen関数でファイルを開く
  3. fgetsで読み込む
  4. fclose関数でファイルを閉じる

キーボードからデータを読ませるときは、1と2と4の手順は要らず fgetsだけで良かった。以下は、標準入力から 読んだデータを行番号をつけて表示するプログラムである。

cat-n.c

#include <stdio.h>
#define BUF_LEN	200

int main()
{
  char buffer[BUF_LEN];
  int  n=0;
  while (NULL != fgets(buffer, sizeof buffer, stdin)) {
    printf("%4d: %s", ++n, buffer);
  }
}

挙動を確かめるため、試しにコンパイルと実行をしてみよう。

% gcc -o cat-n cat-n.c
% ./cat-n
てきとうに
何行か入れて、
最後の行でこんとろーるDをおす
[C-d]
% cat aisatsu.c | ./cat-n

では、データを必ず aisatsu.c (第4回に作った) から読み込むように fopen, fclose を利用して改良してみよう。

fcat.c

#include <stdio.h>
#define BUF_LEN	200

int main()
{
  FILE *aisatsuin;
  char buffer[BUF_LEN];
  int  n=0;
  aisatsuin = fopen("aisatsu.c", "r");
  while (NULL != fgets(buffer, sizeof buffer, aisatsuin)) {
    printf("%4d: %s", ++n, buffer);
  }
  fclose(aisatsuin);
}

コンパイルし、プログラムを起動すると自動的にデータファイルとして aisatsu.c を開き、行番号をつけた結果を出力する。

ファイルから入力させるために施した修正点について説明しよう。

ファイルへの書き出し

fprintfによるファイルへの書き出し

fprintf関数を使うと、 fopenで書込モードでオープンしたファイルに書き出せる。

FILE *kakikaki;
  :
kakikaki = fopen("hello.dat", "w");
  :
fprintf(kakikaki, "Hello, world!\n");
  :
fclose(kakikaki);

fprintf関数は、printf関数と同様に 書式つきの出力を行なう。第1引数に出力先ストリームを指定する点を 除いてprintf関数と同じだと思って良い。

printf("%s は %d 円です.\n", item, price);
  は以下と同じ
fprintf(stdout, "%s は %d 円です.\n", item, price);

例外処理

fopen を利用したプログラムでは、

開こうとしたファイルが存在しない!!

ということがごく普通にありうるので、プログラムを書くときは、 「開くファイルがなかった場合」つまり、fopen()に 失敗した場合を必ず考えなければならない。具体的には、fopen() 関数の返却値が NULL の場合の対処を書く必要がある。

開こうとしたファイルがなかったら、続く処理が何もできないことが 多いだろうから、以下のような流れを書けば良い。

FILE *datafile;
char buf[100];
datafile = fopen("hissu.data", "r");
if (NULL == datafile) {
  fprintf(stderr, "hissu.data ファイルを用意して下さい\n");
  exit(1);    /* exitはプログラムの実行を終了 */
}
while (NULL != fgets(buf, 100, datafile)) {
  :
  : (本当の処理)
}

fprintfの出力先として指定している stderrは、標準エラー出力 と呼ばれるもので、 エラーメッセージを出すためのストリームである。エラーメッセージを

if (NULL == datafile) {
  /* ↓ エラーメッセージにprintfはダメ! */
  printf("hissu.data ファイルを用意して下さい\n");
  exit(1);    /* exitはプログラムの実行を終了 */
}

のように標準出力に出した場合

% cat aisatsu.c | ./cat-n > hogehoge.out

のように、リダイレクトされた場合エラーメッセージまで hogehoge.out ファイルに行ってしまって、エラーになったかどう かが利用者には分からない。標準エラー出力 (stderr)に出すようにすれば、たとえリダイレクトされても 必ず画面にメッセージが出るようになる。


目次