たいていのプログラムでは、起動したらなんらかのデータを読み込む。 そしてデータを処理した結果を書き出す。 プログラムによっては、毎回必ず同じデータを読むことがある。たとえば 商品と値段表や、学籍番号と名前、などのように一度決まったら しばらく同じものを使うような性質のデータを処理する場合である。 そのような場合は、決まったデータをファイルに保存しておいて、 プログラムが勝手にそのファイルを開いてデータを読み込むようにしておくと 都合が良い。
データの読み込みや書き出しを特定のファイルに対して行なうための
関数が fopen/fclose である。
ファイルから、データを読むためには以下の手順を取る。
fopen関数でファイルを開く
 fclose関数でファイルを閉じる
キーボードからデータを読ませるときは、1と2と4の手順は要らず fgetsだけで良かった。以下は、標準入力から 読んだデータを行番号をつけて表示するプログラムである。
#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 を利用して改良してみよう。
#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 を開き、行番号をつけた結果を出力する。
ファイルから入力させるために施した修正点について説明しよう。
FILE *aisatsuin;
      FILE構造体へのポインタを持つ変数を宣言している。
FILE構造体とは、開くファイルに関する様々な情報を
      まとめて記憶しておくための型である。「構造体」に関しては後期に
      学習する。変数名の直前についている * は、その変数は
      値を持つのではなく、値が入っている「アドレス」を持つのだということ
      を意味している。アドレスを持つための変数のことをポインタ変数
      という。
ファイルを開くために宣言する変数については、あまり中味にこだわっ てもしかたないので、
ファイルを開くときは、そのファイルの情報を持つ変数を
FILE *で宣言すれば良い
とだけ覚えておけば良い。
aisatsuin = fopen("aisatsu.c", "r")
      実際にファイルを開き、その情報をaisatsuinに代入する。
      fopen関数の利用書式は
      以下のとおり。
fopen - ファイルのオープン
	    ファイルを指定したモードで開く
#include <stdio.h> fopen(ファイルのパス, モード)
第1引数に指定したファイルを開く。そのときにモード を表す文字列を指定できる。モードには以下のものがある。
"r"
	     ファイルを読み取るためにテキストモードでオープンする。 ファイルの先頭から読む。
"r+"
	     ファイルを読み取りと書き込みのめにオープンする。 ファイルの先頭から読む。
"w"
	     書き込み(新規作成)モードで開く。既存のファイルは0バ イトにクリアされる。
"w+"
	     読み書きモードで開く。既存のファイルは0バイトにクリ アされる。
"a"
	     書き込みモードで開く。ファイルが既に存在する場合は ファイルの終わりから開始し、なければ新規に作成する。
"a+"
	     読み書きモードで開く。ファイルが既に存在する場合は ファイルの終わりから開始し、なければ新規に作成する。
ファイルのオープンに成功すると、開いたファイルの情報を持
	    つFILE構造体へのポインタを返す。失敗した場合は
	    NULL を返す。
fgets(buffer, sizeof buffer, aisatsuin)
      fgetsの第3引数にあたえるストリームとして
      開いたファイルへのFILEポインタを指定することで、そのファイルから
      入力するようになる。
fclose(aisatsuin);
      FILEポインタを与えてファイルをクローズする。 忘れやすいので注意!
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)に出すようにすれば、たとえリダイレクトされても
必ず画面にメッセージが出るようになる。