情報処理演習
第14回
2011年1月20日
ファイル入出力
ですが,キーボード入力などもおさらいします
キーボードで入力:
標準入力
という
例)scanf(”%d”,&i) 前回までの講義でファイルからデータを読み込む場合に使用した関数: fscanf 例)fscanf(fin,”%d”,&i) fscanfは,ファイルからの入力以外にも使用できる.ファイルからデータを読み 込んだ場合のfinなどはファイルポインタであったので,ファイルから入力される.したがって,finの代わりに標準入力を示すstdinを使用すれば,fscanfを使用
してキーボード入力ができる. 例)fscanf(stdin,”%d”,&i)
scanfでは,暗示的に標準入力stdinが指定されている.
つまり,
scanf(”
%d”,&i) と fscanf(stdin,”%d”,&i)
は同一
コンソールに表示:
標準出力
という
例)printf(”%d”,i) 前回までの講義でファイルにデータを書き込む場合に使用した関数: fprintf 例)fprintf(fin,”%d”,i) fprintfは,ファイルへの出力以外にも使用できる.ファイルにデータを書き込 んだ場合のfinなどはファイルポインタであったので,ファイルへ出力される.したがって,finの代わりに標準出力を示すstdoutを使用すれば,fprintfを
使用してコンソールへ出力できる. 例)fprintf(stdout,”%d”,i)
printfでは,暗示的に標準出力stdoutが指定されている.
つまり,
printf(”
%d”,i) と fprintf(stdout,”%d”,i)
は同一
標準出力
#include <stdio.h> main() { int c; c=getchar(); putchar(c); } int getchar() 1文字を標準入力する関数.文字を入力するが, 関数自体はint型として定義されている※. int putchar(int c) 1文字を標準出力する関数.文字を出力するが, 引数はint型である. ※1文字を標準する場合でも, 例) a (Enter) と入力する必要がある.つまり,aと,改行を 示す¥nが保存される必要がある.aを表現す るために1バイト必要なのでchar型(1バイト ではaしか記憶できないので問題となる.そこ で,int型(2バイトもしくは4バイト)として 定義されている.
1文字だけの標準入力,標準出力 h14.c
アスキー(
ASCII)形式
ヒトに分かりや易いテキスト(文字)として表現するためのデータフォーマット. 例えば,6やbなどの半角文字は全て1バイト(8 bit, 2進数で8桁)のアスキー コードで表現され,標準出力関数はそのコードをもとに,6やbなどと表示する.バイナリ形式
文字や数字などを全て2進数で表現したもの.全てアスキー形式で表現した方が分かり易いのでは?
例)short型(2バイト)の変数a=16384をアスキー形式およびバイナリ形式で表現 アスキー形式 00110001 00110110 00110011 00111000 00110011 1 6 3 8 3 8 bit × 5 = 40 bit (5バイト) バイナリ形式 16383 (10進数)=0011111111111111 (2進数) 16 bit (2バイト)アスキーデータの方がデータサイズとしては大きくなる.
アスキーデータとバイナリデータ
ファイルポインタの宣言
ファイルを開く
ファイルを読む/書き込む
ファイルを閉じる
FILE *fp;
fp=fopen(”ファイル名”,”モード”);
fscanf, fprintf など
fclose(fp)
ファイル入出力の手順
ファイルを開く: fp=fopen(”ファイル名”,”モード”);
“ファイル名”のファイルを,指定した“モードで開く” モード 動作 ファイルがある場合 ファイルがない場合 r 読み込み ファイル内容を読込可 エラー: NULLを返す w 書き込み 元の内容を破棄して上書き 新規作成 a 追加 最後に追加書き込み 新規作成 r+ 読込&書込 読み込み&書き込み可 エラー: NULLを返す w+ 読込&書込 読み込み&書き込み可 元の内容は破棄される 新規作成 a+ 読込&追加書込 読込&最後に追加書込 新規作成 下記のモードが使用可ファイルのオープン
#include <stdio.h>
main()
{
int a;
float x;
char s[16];
FILE *fp;
scanf(”%d %f %s”,&a,&x,s);
fp=fopen(”test.txt”,”w”);
fprintf
(fp,”%d %f %s”,a,x,s);
fclose(fp);
fp=fopen(”test.txt”,”r”);
fscanf
(fp,”
%d %f %s”,&a,&x,s);
fclose(fp);
printf(”a, x, s = %d, %f, %s¥n”,a,x,s);
アスキーファイルの入出力
#include <stdio.h>
main()
{
int a;
FILE *fp;
a=getchar();
fp=fopen(”test.txt”,”w”);
putc(a,fp)
;
fclose(fp);
fp=fopen(”test.txt”,”r”);
a=getc(fp)
;
fclose(fp);
putchar(a);
}
アスキーファイルの入出力: 1文字入出力
#include <stdio.h>
main()
{
char s[16];
FILE *fp;
scanf(”%s”,s);
fp=fopen(”test.txt”,”w”);
fputs(s,fp);
fclose(fp);
fp=fopen(”test.txt”,”r”);
fgets(s,15,fp)
;
fclose(fp);
printf(”%s¥n”,s);
}
この例の場合,15-1=14個の文 字 が フ ァ イ ル か ら 読 み 込 ま れ , s[0]からs[13]に格納される. s[14]には,文字列の最後を示す ヌル文字(¥0)が格納される.もし, ファイルに書かれていた文字の数 が14個より少ないときは,行の末 尾まで(改行コードが検出されるま で)読み込む.アスキーファイルの入出力: 1行入出力
まず,心電図データをhttp://www.ecei.tohoku.ac.jp/~hasegawa/からダウンロード この2つをダウンロードして下さい. ダウンロードしたファイルは 皆さんが作るCプログラムと 同じディレクトリに保存して 下さい.
バイナリデータの読み込み: 心電図データのダウンロード
#include <stdio.h>
#define nnn 850
main()
{
int i;
float ecg[nnn+1];
FILE *fp;
fp=fopen("./ecg.bin","r
b
");
fread(ecg,sizeof(float),nnn,fp);
fclose(fp);
fp=fopen("./ecg2.txt","w");
for(i=0;i<nnn;++i)
fprintf(fp,"%f¥n",ecg[i]);
fclose(fp);
fp=fopen("./ecg2.bin","w
b
");
fwrite(ecg,sizeof(float),nnn,fp);
バイナリデータを読み込む 読み込んだバイナリデータを, アスキーデータとして保存. (gnuplotで確認するため) 読み込んだバイナリデータを, バイナリデータとして再度保バイナリファイルの入出力
fopenのモード指定
モードの指定は,アスキーデータの場合はこれまで”r”(読み込み)もしくは”w”(書き 込み)のみ指定していましたが,バイナリデータの場合は,”rb”(読み込み),”wb” (書き込み)を使用します.バイナリデータ読み込み関数fread
使用法: fread(読込データを保存する配列名,sizeof(配列の型),データの数,ファイルポインタ) 例: fread(ecg,sizeof(float),nnn,fp) 意味: ファイルポインタfpが示すファイルから,floatのサイズ(4バイト)のデータを nnn個読み込んで,配列ecgに格納.格納するときのデータ型は配列の型とする. ※sizeof()は,カッコ内に指定したデータ型のサイズを示す.バイナリデータ書き込み関数fwrite
使用法: fwite(読込データを保存する配列名,sizeof(配列の型),データの数,ファイルポインタ) 例: fread(ecg,sizeof(float),nnn,fp) 意味: 配列ecgのnnn個の要素それぞれを,その配列のデータ型(float)の サイズ(4バイト)でファイルポインタfpが示すファイルに書き込む.バイナリデータ入出力方法
[xxxxxxxxxxxxxxxxxxxxxxxxxx]% ファイルサイズ (bytes)
ecg.binは,ecg.txt(アスキーデータ)をバイナリデータに変換
しただけですが,アスキーデータ(ecg.txt)に比べ,バイナリ
データ(ecg.bin)はかなり小さくなっていることが分かります.
アスキーデータとバイナリデータのサイズの違い
[xxx]% gnuplot
gnuplot> plot ”ecg.txt” w l gnuplot> replot ”ecg2.txt” w l
ecg.binが正常に読み込まれていれば,ecg.txtとecg2.txtは一致
[xxxxxxxxxxxxxxxxxxxxxxxxxx]% ファイルサイズ (bytes)
・ecg.binは,ecg.txt(アスキーデータ)をバイナリデータに変換
しただけですが,アスキーデータ(ecg.txt)に比べ,バイナリ
データ(ecg.bin)はかなり小さくなっていることが分かります.
・ecg2.binが正常に書き込まれていれば,元のデータファイル
ecg.binのサイズと同一になります.
fwrite による書き込み結果の確認
http://www.ecei.tohoku.ac.jp/hasegawa/ の第14回のところにある課題用データ(data.bin)をダウンロードする. データファイルdata.binには,本資料13ページで扱ったecg.binと同様に数値 デ ー タ が バ イ ナ リ 形 式 で 保 存 さ れ て い る ( 1 行 に 羅 列 ) . デ ー タ の 数 は 75×75=5625,データの型shortである.data.binのデータを,本講義資料 13ページのプログラムと同様の要領でfreadを用いて読み出して配列img[i] に格納する.読み込んだデータは75点×75点の画像データなので,次ページ 以降の要領でgnuplotで3次元表示できる形式のテキストファイル(data.txt)に 保存するプログラムを作成して下さい(data.txtのデータの並べ方は,第4回資 料8ページも参考になると思います). ※まずは,本資料13ページのようにファイルからfreadを用いてバイナリデー タを配列img[i]に格納するところを参考にプログラムを作り始めて下さい. 後は,配列img[i]の内容をgnuplotで表示できるようにテキストファイルに 保存すればOKです.
課題Q14-20110120
i = 0, j = 0のデータ i = 1, j = 0のデータ i = 2, j = 0のデータ ・ ・ ・ i = 73, j = 0のデータ i = 74, j = 0のデータ i = 0, j = 1のデータ i = 1, j = 1のデータ ・ ・ ・ i = 74, j = 1のデータ i = 0, j = 2のデータ ・ ・ ・ ・ ・ ・ i = 74, j = 74のデータ 全部で75×75個のデータ 0 1 2 ... 74 = 0 1 2 ... 74 = i データが並んでいるイメージ 画像 (点の集合) 画像は点の集合 2次元画像であれば,座標 (i, j) の点の色を 数値データで表現する.
data.bin に入っているデータの構造
img[0] img[1] img[2] img[3] ・ ・ ・ ・ ・i番目 i=1 i=2 i=3 ・ ・ ・ ・ ・ i=74 i=75 波形 j j = 1 j = 2 j = 3 ・ ・ ・ ・ ・ j = 74 j = 75 gnuplotの3次元表示で下記のように 表示されるようにしたい 各マスには波形iのj番目の数値データが 色で表示される.
gnuplot で表示させたときのデータの並び
i = 0, j = 0のデータ i = 1, j = 0のデータ i = 2, j = 0のデータ ・ ・ ・ i = 73, j = 0のデータ i = 74, j = 0のデータ i = 0, j = 1のデータ i = 1, j = 1のデータ ・ ・ ・ i = 74, j = 1のデータ i = 0, j = 2のデータ ・ ・ ・ ・ ・ ・ i = 74, j = 74のデータ データが並んでいるイメージ img[0] img[1] img[2] img[3] ・ ・ ・ ・ ・変換前データファイルdata.bin i= 0, j= 0のデータ i= 1, j= 0のデータ i= 2, j= 0のデータ ・ ・ ・ i=73, j= 0のデータ i=74, j= 0のデータ i= 0, j=1のデータ i= 1, j=1のデータ ・ ・ ・ i=74, j=1のデータ i= 0, j=2のデータ ・ ・ ・ ・ ・ ・ i=74, j=74のデータ 変換後データファイル(ファイル名は何でも良い) i j データ 0 0 i= 0, j= 0のデータ 1 0 i= 1, j= 0のデータ 2 0 i= 2, j= 0のデータ ・ ・ ・ 73 0 i=73, j= 0のデータ 74 0 i=74, j= 0のデータ 0 1 i= 0, j=1のデータ 1 1 i= 1, j=1のデータ ・ ・ ・ 74 1 i=74, j=1のデータ 0 2 i= 0, j=2のデータ ・ ・ ・ ・ ・ j(行)の変わり目に 空行が必要
データをファイルに出力する際の並べ方
j(行)の変わり目に 空行が必要[xxx]$ gnuplot
・
・
・
gnuplot> set pm3d map
gnuplot> splot ”data.txt”
※変換後データファイル名がdata.txtの場合
並べ替えた結果が正しいかどうかは
表示結果を見ればすぐに分かると思います.
24
課題(Q4-20101028c) ※参考
本資料7ページで計算した関数
z = sin(x)·sin(y)
は,
x, y, z の3次元データであるため,グラフ表示も3次元にする必要がある.
本資料7ページのプログラムで計算したデータを,次ページに記す,gnuplot
で3次元表示するためのフォーマットに並べ替えてアスキー(テキスト)ファ
イルに保存するプログラムを作成して下さい.
※ 前ページのプログラムの計算結果を,次のページで説明してある形式で
ファイルに出力する方法を考える,ということです.
gnuplot は3次元表示も可能
[xxx]$ gnuplot
gnuplot> set pm3d
gnuplot> splot ”result.txt”
x y z の値 -3.000000 -3.000000 0.019915 -2.400000 -3.000000 0.095321 -1.800000 -3.000000 0.137429 -1.200000 -3.000000 0.131529 -0.600000 -3.000000 0.079682 -0.000000 -3.000000 0.000000 0.600000 -3.000000 -0.079682 1.200000 -3.000000 -0.131529 1.800000 -3.000000 -0.137429 2.400000 -3.000000 -0.095321 3.000000 -3.000000 -0.019915 -3.000000 -2.400000 0.095321 -2.400000 -2.400000 0.456250 -1.800000 -2.400000 0.657798 -1.200000 -2.400000 0.629558 -0.600000 -2.400000 0.381395 -0.000000 -2.400000 0.000000 0.600000 -2.400000 -0.381395 1.200000 -2.400000 -0.629558 1.800000 -2.400000 -0.657798 2.400000 -2.400000 -0.456251 3.000000 -2.400000 -0.095322 -3.000000 -1.800000 0.137429 -2.400000 -1.800000 0.657798 -1.800000 -1.800000 0.948379 -1.200000 -1.800000 0.907664 -0.600000 -1.800000 0.549876 . . . . . . . . . 3次元表示に必要なファイルの構造
x
y
z
y = 0 の場合の データ y = 1 の場合の データ y の値が変わ る と こ ろ に 空 行 が 必 要 点と点の間隔を細かくして滑らかに表示させるなど 工夫してみて下さい.様々な関数を表示できます.gnuplotで3次元表示するためのファイルフォーマット ※参考
z
今回は set pm3d map と入力.
#include <stdio.h> #include <math.h> #define pi 3.1416 #define kizami 12 main() { int i,j; float phase,phase2,result; FILE *fout; fout=fopen("result.txt","w"); for(i=0;i<kizami;++i){ for(j=0;j<kizami;++j){ phase=2*pi*i/kizami; phase2=2*pi*j/kizami; result=sin(phase)*sin(phase2); fprintf(fout,"%d %d %f¥n",i,j,result); } fprintf(fout,"¥n"); } fclose(fout); }