主なファイルのオープンの方法("w+"などのオプションもある。man fopen を参照せよ。)
返り値は、FILE * 型。fgets や fprintf に使用可能。返り値が NULL ならば、オープンに失敗。
ファイルをオープンすることは、計算機のファイル管理のリソースを消費 するので、使わなくなったファイルは、クローズする必要がある。
fclose の引数には、fopen の返り値を代入する。
ファイルを書き込みオープンし、文字列 "Hello" をファイルに書き込もう。
/* list0601.c */ #include <stdio.h> #include <stdlib.h> int main(){ FILE *fout; fout = fopen("test0601.dat","w"); // 書き込みオープン if( fout == NULL ) { fprintf(stderr,"File open error\n"); exit(1); } fprintf(fout,"Hello"); // fout を通じて書き込む fclose(fout); // fout をクローズ return 0; } |
less コマンドで、test0601.dat の中身を見てみよう。
ファイルをオープンして、文字列の読み書きをするプログラムは、fgets や fprintf を使用して実現できる。しかし、NameCard のような構造体のファ イルの読み書きには、fgets や fprintf よりも fread や fwrite のほうが効率 的である。
書式は以下の通りである。
fread( データの格納先(ポインタ), データの1つぶんの大きさ, データの個数, 読み込み元 );
fwrite( データのありか(ポインタ), データの1つぶんの大きさ, データの個数, 書き込み先 );
使用例を以下に示す。
/* list0602.c */ #include <stdio.h> #include <stdlib.h> #define MAX 10 #define SIZ 100 typedef struct { int id; // 学生の ID 番号 int score; // 点数 char grade; // 評価の文字: A B C } Score; int main() { Score *score_list; int i; char tmp[SIZ]; FILE *fout; // MAX 人分の Score を用意する。 if( ( score_list = (Score *)malloc(sizeof(Score) * MAX) ) == NULL ){ fprintf(stderr,"malloc failed\n"); exit(1); } // MAX 人分の ID と点数を標準入力より入力する i = 0; while( fgets(tmp, SIZ, stdin) != NULL ){ // MAX 人に満たない人数のとき NULL if( i >= MAX ){ fprintf(stderr,"overflow\n"); exit(1); } // 2つの数字が正しく入力されなかったとき、2 以外が sscanf から返される if( sscanf(tmp,"%d %d", &(score_list[i].id), &(score_list[i].score)) != 2 ){ fprintf(stderr,"syntax error\n"); exit(1); } // 点数が、90 点以上ならば A, 80点以上ならば B, それ以下ならば C とする。 if( score_list[i].score >= 90 ) score_list[i].grade = 'A'; else if( score_list[i].score >= 80 ) score_list[i].grade = 'B'; else score_list[i].grade = 'C'; i += 1; } // ファイルの書き込み if( (fout = fopen("test0602.dat","w")) == NULL ){ fprintf(stderr,"file oepn failed\n"); exit(1); } // ヘッダの出力 if( fprintf(fout,"%d\n", MAX) < 0 ){ // fprintf の返り値が負ならばエラー fprintf(stderr,"failed to save\n"); exit(1); } // データの出力 if( fwrite( score_list, sizeof(Score), MAX, fout ) < 0 ){ // fwrite の返り値が負ならばエラー fprintf(stderr,"failed to save\n"); exit(1); } fclose(fout); return 0; } |
構造体の使用方法についても理解してもらいたいが、この例題では、「ファイルの書き込み」以降に重点を置いて理解してもらいたい。
test0602.dat というファイルが、例題2のプログラムより生成される。そこで、test0602.dat を読み込み、その内容を表示するプログラム(prac0601.c)を作成せよ。
/* prac0601.c */ #include ??? #include ??? ? 構造体 Score を定義する int main() { ??? fin; // 読み込み用ファイルデスクリプタ int size, i; ??? score_list, *tmp; // 格納先と一時的な変数 fin = ?? ファイルの読み込みオープン ?? fin が NULL ならばエラー終了 if( fscanf(fin, "%d\n", ???? ) <= 0 ){ // データ数を読み込む。size に代入 ?? エラー終了 } score_list = ?? 格納先のメモリ確保 ?? エラーチェック ?? fread を使って読み込み ?? クローズ for( i = 0; i < size; i += 1 ){ tmp = &score_list[i]; printf("%d %d %c\n", tmp->id, tmp->score, tmp->grade); } return 0; } |
課題を完成させよ。下記のとおり入力に対する出力が得られることを確認せよ。また、「0 0」が余分に表示されないようにするためには、どのようにプログラムを変更すればよいか?
小レポートには、(1)prac0601.c のソースコード、(2)手書きによるコメント、および、(3)「0 0」の表示されないようにする工夫の説明文を記載せよ。
(入力例) 1 90 2 80 3 70 4 60 5 78 6 98 (ここで、Control-Dを押す) (出力例) 1 90 A 2 80 B 3 70 C 4 60 C 5 78 C 6 98 A 0 0 0 0 0 0 0 0 |