第 3 回プログラミング応用 目的ファイル入出力 1. ファイルの概念 2. ファイルの読み込み 3. ファイルの書き込み
CPU 演算 判断 ファイルの概念 内部記憶装置 OS 機械語プログラム 入力装置 キーボード 出力装置 ディスプレイ ファイル 外部記憶装置ハードディスク CD-ROM CPU が外部とデータをやり取りするための媒介 printf 関数や scanf 関数でもうすでにファイルのやり取りの基本は学んでいる ハードディスクの中身 00 30 42 23 43 10 21 95 21 64 02 83 47 39 85 20 83 70 32 94 21 18 04 62 32 42 53 74 26 84 16 38 test.c #include <stdio.h> int main() { int det,a[2][2]; A[0][0] = 2; A[0][1] = 1; A[1][0] = 4; A[1][1] = 3; det = /* 行列式の計算を書く */ printf(" A = %d n", det); return 0; ファイルを読むには保存場所 フォーマットなどファイルを作るには空きのある場所ある程度 OSが面倒見てくれる
C 言語でのファイル操作の流れ ファイルのオープン ファイルポインタを取得 読み書きモードの指定 (fopen 関数 ) ファイルポインタはファイルに関する様々な情報をまとめて入れておく変数 ファイルの読み書き処理 ファイルポインタに対して読み書き処理を行う (fprintf, fscanf 関数等 ) printf 関数 scanf 関数と同じ使い方 ファイルのクローズ ファイルポインタを開放して ファイル他から使えるようにする (fclose 関数 ) 開いたファイルは必ず閉じる
変数宣言部分 ファイルへのオープン FILE *fp; FILE 型変数の宣言 大文字でFILE ファイル情報を入れておく箱宣言時には変数名の前に必ず *( アスタリスク ) を付ける操作したいファイルとファイルポインタは1 対 1に対応する同時に複数個のファイルを操作したいときは複数のファイルポインタを宣言しておく 命令文部分 (fopen 関数 ) fp=fopen( ファイル名, モード ); 必ずファイルポインタ変数への代入文の形で書く モードには 読み込みのとき r 書き込みのとき w の文字を指定 ファイルが正しくオープンできたとき fp にファイルポインタが入る ファイルポインタには現在ファイル中のどこを読んでいるかの情報も入っている
ファイルへの書き込み 今まで使っていたprinf 文の表記と類似ファイルポインタを指定して 書き込むファイルを指定する ファイルへの書き込み fprintf( ファイルポインタ, 出力文字列や変換文字, 変数名 1, ); 書き込みモードで開かれたファイルに対して使用 変換文字と代入する変数のデータ型は一致させる 第三引数以降は数値を指定する. 変数で表される数値でもよい ファイルのクローズ fclose( ファイルポインタ ); 開いたファイルは必ず閉じる
演習 3-1 #include <stdio.h> output.c int main() { FILE *fp; /* ファイルポインタの宣言 */ fp=fopen( test.txt, w ); /* ファイルを書き込みモードで開く */ fprintf(fp, This is test. n ); /* 開いたファイルに文字を出力する */ fclose(fp); /* ファイルを閉じる */ return 0; 1. 実行して test.txt というファイルが作られていることを確認せよ. >ls ディレクトリ内容表示コマンド >cat ファイル名ファイル内容表示コマンド 2. ファイル名を変えたり, 出力する文字を変えたりして期待通りの結果になるか確認せよ 3.data.txt というファイル名で for 文を用いて 10 行 2 列の数字データを出力してみよ ( 答えは最後のスライド )
数値データファイルの読み込み ファイルからの読み込み fscanf( ファイルポインタ, 変換文字, & 変数名 1, ) 読み込みモードで開かれたファイルに対して使用 変換文字(%dとか%f 等 ) と代入する変数のデータ型は一致させる fscanfでも変数名の前に & をつける. for(i=0;i<7;i++){scanf( %d,&a[i]); キーボードから for(i=0;i<7;i++){fscanf(fp, %d,&a[i]); ファイルポインタ fp のファイルから入力
fscanf 関数の注意点 数値データファイル fp=fopen( test.dat, r ); for(i=0;i<7;i++){ fscanf(fp, %d,&a[i]); ひとかたまりの数値を 1 個だけ読みこんで 整数として代入 test.dat 1 20 31 4 52 6 78 fscanf 関数はファイル中の数値データをスペースや改行を区切りとして指定個数読み込む 読み込む順番は左 右 その行が終われば, 次行の一番左から右に順に読まれる fscanf 関数が読んだ最後の位置はファイルポインタが記憶している 同じファイルを続けて fscanf 関数で読めば 続きの場所から読み込まれる 一旦開いたファイルは順番を飛ばしたり 反対方向に戻って読むことはできない a[0] a[1] hensuu a[2] a[3] a[4] hensuu a[5] a[6]
演習 3-2 ファイルから NUM 個の数値データを読み込んで 端末画面に表示させるプログラム input.c #include <stdio.h> #define NUM 10 int main() { FILE *fp; ファイルポインタの宣言 int i,data[num]; 配列変数 dataの定義 fp=fopen( data.txt, r ); data.txtを読み込みモードで開く for(i=0;i<num;i++) { 中カッコ内をNUM 回繰り返す fscanf(fp, %d,&data[i]); 配列変数 dataのi 番目の要素にファイルから 読み込んだ数値データを順次代入していく fclose(fp); for(i=0;i<num;i++) { printf( %d n,data[i]); return 0; 中カッコ内をNUM 回繰り返す配列変数 dataの要素を出力して改行する 1. 演習 3-1 で作った数値データファイルがあることを確認した後, これを実行してみよ 2. 読み込むデータの数を増やしてみよ,20 以上を指定するとどうなるか確認せよ 3. 存在しないファイル名を指定するとどうなるか確認せよ
ファイルオープンのエラー処理 ファイルの読み書き関数は取得したファイルポインタに対して行う もしファイルポインタを正しく取得できなければ ファイルの読み書き関数はハードディスクの間違った場所を読んだり 書き込んだりしてしまい他のファイルが損傷する恐れがある ファイルポインタが正しく取得できない ( 読み込みモードでファイルが存在しない ) とき fopen 関数は NULL という値 ( 定数 ) を返すようになっている #include <stdio.h> int main() { FILE *fp; ファイルポインタの宣言 fp=fopen( test.txt, r ); test.txtを読み込みモードで開きファイルポインタを取得 if (fp==null){ test.txtが存在しないとき printf( Can t open file n ); メッセージを表示 return 1; 強制的にプログラムを終了する 通常は異常終了をさせないようこのようなエラー処理をすることで安全に終了させる
課題 3 10 人以上の得点データ ( 適当に考えてよい ) が入ったInput.txtという数値データファイルを emacsで作成し プログラムで読み込む その後 得点の平均値を計算する さらに output.txtにデータ番号 その得点 ( 得点 - 平均値 ) を出力せよ kadai3_sample.c #include <stdio.h> # define NUM 10 int main() { FILE *fpi,*fpo; /* 読み込み 書き込み用ファイルポインタの宣言 */ int i,data[num]; /* カウンタ変数 i, 得点データ用配列変数 dataを定義 */ float ave,sum=0; /* 総得点用の変数 sum, 平均値用の変数 aveを宣言 */ input.txt を読み込みモードで開く文を fopen 関数を使って書く fpi=fopen( input.txt, r ); if (fpi==null){ /* input.txtが存在しないときの処理 */ printf( Can t open file n ); /* メッセージを表示 */ return 1; /* 強制的にプログラムを終了する */ input.txtから得点データをnum 人分読み 配列変数 data[] に代入する部分をfor for(i=0;i<num;i++){fscanf(fpi, %d,&data[i]); 文,fscanf 関数を使って書く for(i=0;i<num;i++){sum=sum+data[i]; /* 変数 sum に配列 data[i] の値を加えていく */ ave=sum/num; /* 総得点 sum を人数 NUM で割って平均値 ave を計算 */ fpo=fopen( output.txt, w ); /* output.txtを書き込みモードで開く */ for(i=0;i<num;i++){ ここで人分のデータ番号と 得点 ( 得点データ- 平均値 ) をファイルに出力 fprintf(fpo, %d %d %f n,i,data[i],(data[i]-ave)); する部分をfor 文 fprintf 関数を使って書く fclose(fpi); fclose(fpo); 提出物 : C ソースファイル output.txt 締め切り : 次回講義開始日 12:00 まで提出方法 : HP に記載 ( 課題番号は 3)
#include <stdio.h> 演習 3-1-3 解答例 data.txt というファイル名で for 文を用いて 10 行 2 列の数字データを出力してみよ int main() { FILE *fp; /* ファイルポインタの宣言 */ int i; /* ループのためのカウンタ変数宣言 */ fp=fopen( data.txt, w ); /* ファイルを書き込みモードで開く */ for(i=0;i<10;i++){ /* 10 行書き込み分 10 回ループ */ fprintf(fp, %d %d n,i,i*i); /* 横に 2 個並んだ数値を出力し改行する */ fclose(fp); /* ファイルを閉じる */ return 0; これと同じ fprintf(fp, %d %d n,0,0); fprintf(fp, %d %d n,1,1); fprintf(fp, %d %d n,2,4);.. fprintf(fp, %d %d n,9,81); data.txt 0 0 1 1 2 4 3 9 4 16 5 25 6 36 7 49 8 64 9 81