たいていのプログラムでは、起動したらなんらかのデータを読み込む。 そしてデータを処理した結果を書き出す。 プログラムによっては、毎回必ず同じデータを読むことがある。たとえば 商品と値段表や、学籍番号と名前、などのように一度決まったら しばらく同じものを使うような性質のデータを処理する場合である。 そのような場合は、決まったデータをファイルに保存しておいて、 プログラムが勝手にそのファイルを開いてデータを読み込むようにしておくと 都合が良い。
データの読み込みや書き出しを特定のファイルに対して行なうための
関数が 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)に出すようにすれば、たとえリダイレクトされても
必ず画面にメッセージが出るようになる。