プログラミングおよび演習 NO.12 |
ファイル処理 |
例12-1(波形データのファイル書き込み)#include <stdio.h> #include <math.h> #include <stdlib.h> void make_coswave(int,float,float,float,float *); void make_sinwave(int,float,float,float,float *); void add_data(int, float*,float*); void file_write(int,float *); int main(void) { float x1[10000], x2[10000];/* 配列x1,x2の宣言 */ int len=10000; /*データの数*/ float SampFrq=5500.0;/*サンプリング周波数*/ float freq1=440; /*1番目の信号の周波数*/ float freq2=444; /*2番目の信号の周波数*/ float amp=0.5; /*信号振幅*/ float tdel; /*時間きざみ*/ tdel=1.0/SampFrq; make_coswave(len,freq1,tdel,amp,x1); /*コサイン波1の生成*/ make_sinwave(len,freq2,tdel,amp,x2); /*サイン波2の生成*/ add_data(len,x1,x2);/*波1,2の加算*/ file_write(len,x1);/*ファイル書き込み*/ return(0); } /*コサイン波の波形データを 配列xに入れる*/ void make_coswave(int len, float freq,float tdel,float amp,float *x) { int i; /* 未完成の部分は自分で作る */ ‥‥ for(i=0;i<len;i++){ ‥‥ x[i]=‥‥; } } /*サイン波の波形データを 配列xに入れる*/ void make_sinwave(int len, float freq,float tdel,float amp,float *x) { int i; /* 未完成の部分は自分で作る */ ‥‥ for(i=0;i<len;i++){ ‥‥ x[i]=‥‥; } } void add_data(int len,float *x1,float *x2) { int i; for(i=0;i<len;i++) x1[i]=x1[i]+x2[i]; } /* 配列xのデータをファイルに書き込む。*/ void file_write(int len, float *x) { int i; FILE *fp; /* ファイルポインタの宣言 */ char name[30]; printf("\nfilename?="); fflush(0);scanf("%s",name); /*ファイル名のキーボード入力*/ if((fp=fopen(name,"w"))==NULL){/*ファイルオープン*/ printf("\nCan't open the source file\n"); /* ファイルオープンに失敗した時のエラーメッセージの出力 */ exit(1); } for(i=0; i<len; i++) fprintf(fp,"%4.3f\n",x[i]); /*データx[i]の書き込み*/ fclose(fp); /*ファイルクローズ */ } |
補足(どこのフォルダにファイルが書き込まれるか)
例12.1のプログラムをEclipseの画面上で実行すると、ワークスペースフォルダ内の下記の場所(project名フォルダ)にファイルが書き込まれます。
z:\workspace\project名
ただし、Eclipseのワークスペースフォルダ(Eclipse の初期設定の際に、設定したフォルダ)を、z:\workspace以外のフォルダに設定している場合は、これとは違う場所になります。
演習問題12-1 (Revised : 2016/11/25) (1)例12-1を参考にして、振幅が同じで周波数が異なる2つのサイン波データを足し合わせて、結果をファイルに書き込むプロブラムを作ってください。 ここで、振幅と周波数の組合せは、1.0と 1.0 kHz、および、1.0と2.0 kHzとします。 ただし、サンプリング周波数は10 kHzとしてください。 プログラムが正常に動作していれば、指定した名前のファイルが出来上がります。エクスプローラで自分の作業フォルダを開いて確認してください。 また、先週の演習問題11-3と同じやり方でエクセルにデータを読み込み、波形をグラフに描いてみてください。 実行前に予測した波形と一致しているかの確認は必ず行って下さい。ここでは考察として、プログラム全体の動作説明と、file_write関数の中で何を行っているかについて説明をしてください。 (2)次に、上で作ったプログラムの下に、(振幅,周波数)=(1.0,1.0kHz)のサイン波と、(振幅,周波数)=(1.0,2.0kHz)のコサイン波の足し算の結果を別の名前のファイルに書き込むプログラムを追加してください。 サンプリング周波数は(1)と同じとします。また、エクセルを用いてグラフにしてください。 最後に、ファイル名として(1)と同じ名前を指定して実行した場合の結果についても示し、考察してください。 注:ファイルに書き込んでいますので、先週のようにコンソール画面の出力リストをコピーしなくても済みます。エクセルで[ファイルを開く]を選び、ファイルの種類のところで、*.txt形式のファイルを選んで読み込んでください(今日の問題は、データ数を10000に増やしています。 この場合、先週のように画面をコピーするやり方は難しいことがわかります)。 |
例12-2(ファイルから読み込んだデータの画面表示)(Revised : 2012/12/3)#include <stdio.h> #include <stdlib.h> void file_read(int *,float *); void disp_data(int,float *); int main(void) { int len; float x[10000]; /* データ配列xを宣言 */ file_read(&len,x); /* 配列x[]に指定のファイルからデータを読み込む */ disp_data(500,x); /* 配列x[]のデータを画面表示する:データの確認。*/ return(0); } void file_read(int *len, float *x) /* ファイル読み込み */ { FILE *fp;/* ファイルポインタの宣言 */ char name[30]; printf("\nfilename?="); /* ファイル名の入力 */ fflush(0);scanf("%s",name); if((fp=fopen(name,"r"))==NULL){ /* ファイルオープン */ printf("\nCan't open the source file\n"); exit(1);/* プログラム終了 */ } *len=0; while(1){ /* 配列x[]にファイルからデータを読み込む.データが最後になったら終了する */ if(fscanf(fp,"%f",&x[*len])==EOF) break; *len=*len+1; /*データの数を数える */ } fclose(fp); /* ファイルのクローズ */ } void disp_data(int len, float *x) /* データの画面表示 */ { int i; for(i=0; i<len; i++) printf("%f\n",x[i]); } |
演習問題12-2(Revised : 2012/12/4) 例12-2 のプログラムを、配列xに読み込んだ任意の長さのデータがすべて画面に表示されるように修正して下さい。また、演習12-1で作成した波形データのファイルを読み込んで画面表示してください。なお、表示結果をレポートで送付する際は、最初の10行と最後の10行のみを添付し、途中は省略すること。考察では、file_read関数の各々の所で何をやっているか説明してください。 [補足説明] 演習12-1で名前を付けて作成した波形データは、z:\workspace\"演習12-1のproject名" のフォルダに入っています。この波形データファイルを、z:\workspace\"演習12-2のproject名" のフォルダにコピーしてから、実行してください。プログラムを実行すると、 filename?= のメッセージがでますので、コピーした波形データファイル名を入力してください。 Can't open the source file というエラーが出る場合は、ファイル名が間違っている、または"演習12-2のproject名"のフォルダに波形データが存在しない、の何れかの原因ですのでよく確認してください。 |
データの内部表現 |
例 12-3 /* 文字データのコード出力*/#include<stdio.h> int main(void) { printf("a:%d b:%d c:%d\n",'a','b','c'); printf("0:%d 1:%d 2:%d\n",'0','1','2'); printf("0:%c 1:%c 2:%c\n",48,49,50); return(0); } |
例 12-4 /* アスキーコードの出力*/#include<stdio.h> int main(void) { unsigned char i; for(i=48;i<=122;i++) printf("%d:%c\n",i,i); return(0); } |
型 | 長さ | 範囲 |
short int | 2Byte=16bit | 0~(2^16-1) (=65,535) |
long int | 4Byte=32bit | 0~(2^32-1) (=4,294,967,295) |
float | 4Byte=32bit | 仮数部(23ビット=8,388,608 6~7桁) 指数部(8ビット=256), 符号1bit |
10進数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
16進数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
2進数 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 |
10進数 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16進数 | 8 | 9 | A | B | C | D | E | F |
2進数 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
例 12-5(整数の%d、%x出力,上位バイト、下位バイト取り出し)#include<stdio.h> int main(void) { short ds; int dl; ds=10000; //ds=0x2710; printf("\nds(10進)=%hd",ds); printf("\nds(16進)=%04hx ",ds); printf("\nds(下位)=%02hx ",(ds&0xFF)); printf("\nds(上位)=%02hx\n",(ds>>8)&0xFF); dl=1000000000; //dl=0x3b9aca00; printf("\ndl(10進)%d ",dl); printf("\ndl(16進)%08x\n",dl); printf("\ndl(最下位)%02x ",(dl&0xFF)); printf("\ndl(中下位)%02x",(dl>>8)&0xFF); printf("\ndl(中上位)%02x",(dl>>16)&0xFF); printf("\ndl(最上位)%02x",(dl>>24)&0xFF); return(0); } |
演習問題12-3 (Revised : 2013/12/02) 例12-3,12-4, 12-5のプログラムを次のように変更してください。 (1)例12-3の3つのprintf()文を以下のものに差し替え、「??」に適切な「2桁~4桁の数字」(注:文字ではない)を書き入れてプログラムを完成せよ。 printf("%c%c%c %c%c %c%c%c%c %c%c%c %c%c%c%c\n",??,??,??,??,??,??,??,??,??,??,??,??,??,??,??,??); なお、実行結果は以下の通りとなるようにせよ。 :^) :( :'-( :-@ (:-& (※海外で使われることの多い顔文字で、左から「ハッピー」「悲しい」「泣いている」「叫び」「怒り」を表す) (2)例12-4のプログラムを変更して、キーボードから1文字を入力したら、そのアスキーコード(整数)を出力するプログラムを作ってください。反対に、アスキーコード(整数)を入力したら、文字を出力するプログラムを作ってください。 (3)例12-5のプログラムの変数ds,dlの値を次のように変更してください。プログラムを実行し、実行結果を説明してください。 ds=65534; dl=4294967294; |
バイナリファイル |
例 12-6 /*バイナリデータの書き込み */#include<stdio.h> int main(void) { short ds; FILE *fp; fp=fopen("data.bin","wb"); ds=10000; putc(ds&0xFF,fp); putc((ds>>8)&0xFF,fp); fclose(fp); return(0); } |
例 12-7 /* バイナリデータの読み込み*/#include<stdio.h> int main(void) { short ds; FILE *fp; fp=fopen("data.bin","rb"); ds= getc(fp); ds=ds | getc(fp)<<8; printf("ds=%d(10進) %x(16進)\n",ds,ds); fclose(fp); return(0); } |
演習問題12-4 (Revised : 2014/12/08) 例12-6、12-7のプログラムを次のように変更してください。プログラムを実行すると同時に、プログラムの動作を説明してください。 (1)例12-6を参考にして、300~350までの連続した整数値を、バイナリファイ ルに書き込むプログラムを作ってください。 ・ヒント:書き込み部分を以下のように作ってください。ただし、「?」には適切な数字、文字、記号を書き入れること。 for(ds=???; ds<???;ds??){ putc(ds&0x??,fp); putc((ds>>?)&0x??,fp); } ・出来上がったバイナリファイルを、試しにエディタプログラム(端末室のWindowsPCの場合は”notepad(メモ帳)”や”サクラエディタ”を使ってください)で読み込んでみてください(notepadで開いた場合は文字化けしてしまい読むことができないことを確認してください)。 (2)例12-7を参考にして、上記(1)で作成したバイナリファイル(300~350までの数のバイナリデータ)を読み込んだのち、データを画面に表示するプログラムを作ってください。 [補足説明] 12-4(1)の課題で、保存されたバイナリファイルを、notepadで読み込んだ後、農工大メールに貼り付けて送信しようとすると、 選択された文字コードでは利用できない文字を含んだテキストを送信しようとしています のエラーが出て送信できないことがあります。この場合は次のいずれかの方法を試してください。 方法1:メール送信のテキストのエンコード方法を、日本語ISO-2022-JPではなく、Unicode(UTF8) に変更してください。 方法2: notepadの代わりに、サクラエディタで開いてください(実は、サクラエディタで開くと文字化けしません)。 |
演習問題12-5 (余裕のある人へ) 演習問題12-1では、テキスト形式のファイルを書き込みました。 以下のプログラムは、wavフォーマットのサウンドファイルを作成するプログラムです。 (1)プログラムを実行することによって、サウンドファイルを作成してみてください (この例では、2つのサイン波の合成音(うなり音)を作成しています)。 注:プログラムを実行すると、ファイル名の入力を求めてきますので、 ファイル名を指定してください。その際、ファイル名には、拡張子wavを付けてください。 (2)作成したサウンドファイルを実行して、実際に音を鳴らしてみてください。 注:作成したサウンドファイルを音楽プレーヤ(Windowsの場合はWindows Media Player、MACの場合はQuickTime Playerなど)で聞いてみてください。 (3)他の波形についても行って見てください。いろいろ聞き比べてみると面白いと思います。 /* サウンドファイルの書き込み*/ #include <stdio.h> #include <math.h> #include <limits.h> #define PI 3.14159265358979 void wave_write(int, float,float *); void add_data(int,float *,float *); void make_sinwave(int,float,float,float,float *); float max_data(int,float *); void fputc2hl( unsigned short int, FILE *); void fputc4hl( unsigned long int, FILE *); void fputc2lh( unsigned short int, FILE *); void fputc4lh( unsigned long int, FILE *); int main(void) { long len=10000; long SampFrq=5500; float freq1=440.0,freq2=444.0; float amp=0.5; float x1[10000],x2[10000]; make_sinwave(len,freq1,1.0/SampFrq,amp,x1); make_sinwave(len,freq2,1.0/SampFrq,amp,x2); add_data(len,x1,x2); wave_write(len,SampFrq,x1); return(0); } void wave_write(int len, float SampFrq,float *x) { int i; short dd; float xmax; FILE *fp; char name[30]; xmax=max_data(len,x); printf("\nfilename?="); fflush(0); scanf("%s",name); if((fp=fopen(name,"wb"))==NULL){ printf("\nCan't open the source file\n"); exit(1); } fputs("RIFF",fp); fputc4lh(len*2+36,fp); fputs("WAVE",fp); fputs("fmt ",fp); fputc4lh(16,fp); fputc2lh(1,fp); fputc2lh(1,fp); fputc4lh(SampFrq,fp); fputc4lh(SampFrq*2,fp); fputc2lh(2,fp); fputc2lh(16,fp); fputs("data",fp); fputc4lh(len*2,fp); for(i=0; i<len; i++){ dd=x[i]*32767/xmax; fputc2lh(dd,fp); } fclose(fp); } float max_data(int len,float *x) { int i; float xmax,ax; xmax=0.0; for(i=0;i<len;i++){ ax=fabs(x[i]); if(ax>xmax) xmax=ax; } return(xmax); } void add_data(int len,float *x1,float *x2) { int i; for(i=0;i<len;i++) x1[i]=x1[i]+x2[i]; } void make_sinwave(int len, float freq,float tdel,float amp,float *x) { int i; float time; for(i=0;i<len;i++){ time=tdel*i; x[i]=amp*sin(2.0*PI*freq*time); } } void fputc2hl(unsigned short int d, FILE *fp) { putc(d>>CHAR_BIT,fp); putc(d &0xFF,fp); } void fputc4hl(unsigned long int d, FILE *fp) { putc((d>>CHAR_BIT*3)&0xFF,fp); putc((d>>CHAR_BIT*2)&0xFF,fp); putc((d>>CHAR_BIT )&0xFF,fp); putc(d &0xFF,fp); } void fputc2lh(unsigned short int d, FILE *fp) { putc(d &0xFF,fp); putc(d>>CHAR_BIT,fp); } void fputc4lh(unsigned long int d, FILE *fp) { putc(d &0xFF,fp); putc((d>>CHAR_BIT )&0xFF,fp); putc((d>>CHAR_BIT*2)&0xFF,fp); putc((d>>CHAR_BIT*3)&0xFF,fp); } |