主なファイルのオープンの方法("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 |