4S-RO ロボティクス実験 参考資料 ファイル入出力 : ファイルの読み込み 1 周目に計測した生体情報データを読み込み プログラムにより信号処理を行うが その際にファイルの 入出力が必要となる 実験前半ですでに学習しているが必要に応じて本資料を参考にすること 以下のようにすると指定したファイルを読み込むことができる ( 詳細は後から記述 ) int i; double --------; char fname[100]; // fname はファイル名のために宣言する. // これで 100 文字までのファイル名を読める FILE *data_in; // 変数と同じく最初に宣言.printf などの予約語と同じにしない 同じ名前 data_in=fopen("test.dat","r") // プログラム本体 fclose(data_in); ファイルを開くときの決まりごと rは read 読み込みモード, つまりファイルからデータを読み込むモードとしてアクセスする. これをwにすると write つまりファイルを作成して書き込むからモードとなる 今の場合は同じフォルダ内にある test.dat を読み込みなさい, ということ.Char 型変数 fname[100] に scanf でファイル名を入れて fopen("sin.dat","r") を fopen(fname,"r") とすることで任意のファイル名をオープンできる ファイルポインタとは FILE *data_in; ファイルに関する操作をするときは FILE 型で定義されるファイルポインタを宣言する. 慣れるまでは単純に ファイルを開いたり綴じたりを設定する変数 程度の認識でよい. 読み込み用のファイルを扱うファイルポインタに out とか write とか書き込みをイメージさせる単語は混乱してしまうので使わない. ファイルポインタへのファイルアクセスの指示 :fopen data_in=fopen("test.dat","r") これによりファイルポインタ data_out( アスタリスクは不要 ) には test.dat というファイルを 読み込 み =read モードで 用意しなさいという設定が行われる. モードは 書き込み w 読み込み r 追加
書き込み a がある.w で書きこむときにはは追加ではないのでおなじファイル名を指定すると前のファ イルは消されて上書きされるので注意が必要である. また, 指定がない場合は実行プログラムとおなじフォルダのファイルを読むので別のフォルダにファイルが ある場合はエラーとなる. ファイルを開いたら閉じる fclose(data_in) fclose(test.dat) 使ったら片づける, 開けたら閉める. ファイルもオープンしたらクローズする. ファイルは fopen の段階でアクセス可能な状態になっている. そのままの状態にしておいてプログラムを閉じてしまうとファイルは不安定な状態で待機することになるのでとても危険である. ゆえに, プログラムの最後あるいは用が済んだ段階で必ずクローズすること.( ) の中には閉じたいファイルを操作しているファイルポインタ名を入れる. ファイル名ではない. ただし, 読み込みファイルは 1 指定したファイルが同じフォルダ内に存在すること 2 指定したファイルが C で扱えるデータであること. グラフなどがあるエクセルデータは読めないという条件を忘れないこと. では, 書き込みにたいして何が異なるのかというと, fscanf 関数プログラム中で実際にファイル内のデータを読み込む fscanf(data_in, %d,&a); 内の書式は実際のデータ列および型と一致させる. A 1 B 1 0.1 C 1, a 10 10 0.3 10, b 2 2 1.5 2, c 3 3 2.0 3, d 5 5 1.5 5, e この例では, 読み込むファイルの中身がそれぞれ A: 1 列データで, 型は int B: 2 列データの タブ区切り, 変数は int と float(double). C: 2 列データの カンマ区切り で, 変数は int と char 型. のようにファイルによって異なる. したがって,
ファイルを読み込む場合は, 読み込むべきファイルの形式を一度確認する必要がある これらの例では, 例えば while 文を利用してデータを配列に入れていくとすると A 一列の場合 C データがカンマ区切りの場合,char 型の場合 fscanf(data_in, %d,&n[i]); fscanf(data_in, %d,%c,&n[i],&c[i]); B 二列でデータがタブ区切りの場合の場合 カンマ区切りは fscanf にカンマを入れればよい fscanf(data_in, %d\t%f,&n[i],&x[i]); char 型は読み取りが %c になる.2 バイト文字は %c%c で一文字 元データが改行してあっても,fscanf に改行記号 n は不要 カンマ区切りは fscanf にカンマを入れればよい 実際の読み取り ファイルでデータを読むときはファイルが何行あるか分からない事が普通である. そこで, while を使って EOF を検出するまでデータを読む ようにするのが一般的である. ここでいう EOF は End Of File の頭文字でこの記号があると ここでファ イルはおわりです という意味である. なお, エクセルで自分で打ち込んだデータは最後に EOF を打ち込んでいないので読み込むと空のセル も読み続けるてしまうので注意すること. 以下のように while の条件部分で読み取って, それが EOF じゃなければという繰り返しにする. 時間と電圧値データのタブ区切り 2 列データを配列に読み取る 場合は以下のようになる. i=0; x_sum=0.0; End of File の略 while(fscanf(data_in,"%lf\t%lf",&t[i],&x[i])!=eof) { この時点で t,x にデータは格納される x_sum+=x[i];// 読み込んだデータをすぐに x_sum に足す i ++; fclose(data_in);// この後読み込まないのですぐにクローズしている data_number=i; x_ave=s_sum/(double)data_number; この例では読み込みと同時に合計値も算出している. これはパターンとして覚えてしまったも良い. 配列が 必要かどうかはケースバイケースとなる. 配列を使う場合はデータ個数がいくらか分からないので多めに用 意しておくか動的に確保する.
ファイル入出力 : ファイルの書き込み int i; double x[50]; char fname[100]; // fname はファイル名のために宣言する FILE *data_out; 同じ名前 data_out=fopen("sin.dat","w") 書き込みは w. 書き込みモードとしてアクセスする. ファイル名に日本語は使えるが, 半角英数字 + 拡張子 を使う. 日本語フォルダ / ファイル名, 全角スペースは危険. すでにあるファイルと同じ場合は上書きされる. 自分のフォルダ内で実行し, システムファイルや大事なデータと同じ名前にしない! for (i=0;i<50;i++) { x[i]=(double)i; fprintf は printf の書式に [ どのファイルポインタに対して?] が追加されるだけ 今の場合はファイルポインタ data_out つまりはファイル名 sin.dat に書き込め と言う事 printf( "%ld\t%lf\n",i,x[i]); fclose(data_out); こちらもオープンしたファイルは必ず閉じて終了 ( 重要!) 実際の出力部分は,printf でディスプレイに出力していたことを fprintf にして出力先をファイルにするだ けである.(fprintf では画面に出てこないので確認用の printf と併用することを推奨 ) ファイルへデータを書きこむ部分は, fprintf(data_out," あいうえお \n"); fprintf(sin.dat,"%ld\t%lf\n",i,x[i]); ダメ fopen でファイル名を指定するとき以外は, プログラムにて直接ファイル名を指定する場面はない. 必ずファイルポインタを通して, そのファイルポインタに指定されているファイルをあつかう.
複数のファイルを扱う場合 FILE *V_out, *I_out; V_out=fopen("t-volt.xls","w") I_out=fopen("t-current.xls","w") for(i=0;i<10;i++){ fprintf(v_out, %lf\t%lf,t[i],v[i]); fprintf(i_out, %lf\t%lf,t[i],i[i]); fclose(v_out); // どちらもクローズすること fclose(i_out); // 実はすべてを一気にクローズする fcloseall もある