ファイル入出力
今回はファイル入出力のおさらいと課題を解くにあたっての考え方について簡単に解説したいと思います.
まず、ファイルには主に2つの種類があります
ファイルの種類 | 内容 | 例 |
---|---|---|
テキストファイル | 文字として読めるデータ | .cファイル,.txtファイルなど |
バイナリファイル | 文字として読めないデータ | .pngファイル,wavファイルなど |
ファイルの種類によって使うべきモードが異なることに注意してください.
・テキストファイル
モード | 意味 | 備考 |
---|---|---|
r | 読み込み用にテキストファイルを開く | 既存ファイルがなければエラー |
w | 書き込み用にテキストファイルを開く | 既存ファイルがなければ先に消去 |
a | 既存のテキストファイルの最後に追加 | 元の内容は変更されない |
・バイナリファイル
モード | 意味 | 備考 |
---|---|---|
ra | 読み込み用にバイナリファイルを開く | テキストに準ずる |
wb | 書き込み用にバイナリファイルを開く | テキストに準ずる |
ab | 既存のバイナリファイルの最後に追加 | テキストに準ずる |
ファイルの開閉
通常ファイル処理を行うときは,対象となるファイルを「オープン」「クローズ」する処理が必要となります
関数 | 書式 | 意味 | 使用例 |
---|---|---|---|
fopen() | fopen(ファイル名,モード) | ファイルを指定したモードで開く.戻り値が,ファイルのポインタ | FILE* fp = open("sample.txt","w"); |
fclose() | fclose(ファイルポインタ) | 指定したファイルポインタのファイルを閉じる | fclose(fp); |
ファイル処理においてよく使う関数を紹介致します.
(ただし,int d,char buf[50],FILE *fpの表記をする)
・ファイルへの書き込み
関数 | 書式 | 使用例 |
---|---|---|
fprintf() | fprintf(ファイルポインタ,書き込み文字列,変数・・・) | fprintf(fp,"no=%d",i); |
・ファイルから値の読み込み
関数 | 書式 | 使用例 |
---|---|---|
fscanf() | fscanf(ファイルポインタ,読み込み文字列,変数・・・) | fscanf(fp,"no=%d",&i); |
・ファイルから文字列を一行取得してくれる関数
関数 | 書式 | 使用例 |
---|---|---|
fgets() | fgets(文字列配列のポインタ,一行の最大文字数,ファイルポインタ) | fgets(buf,30,fp); |
・ファイルに文字列を書き込む関数
関数 | 書式 | 使用例 |
---|---|---|
fputs() | fputs(書き込む文字列,ファイルポインタ) | fputs("test",fp); |
・一文字だけファイルから読み込むための関数
関数 | 書式 | 使用例 |
---|---|---|
fgetc() | fgetc(ファイルポインタ) | fgetc(fp); |
よく使う例として
ファイルの末端(EOF)になるまでwhileでループさせて処理する書き方をします
・一文字だけファイルに書き込むための関数
関数 | 書式 | 使用例 |
---|---|---|
fputc() | fputc(書き込む文字,ファイルポインタ) | fputc('a',fp); |
・指定バイト数のデータを指定した個数だけファイルに書き込みます
関数 | 書式 | 使用例 |
---|---|---|
fwrite() | fwrite(データが入ったバッファ,データ1個のバイト数,書き込むデータの個数,ファイルポインタ) | fputc(buf,1,6,fp);//1バイトのデータを6バイト分書き込む |
使用例
これらの関数を使ったサンプルコードを載せます
サンプルコード
#include<stdio.h> int main(void) { char ch[50] = "ABCDEFGH"; char buf[50]; FILE *fp; //ファイルの書き込み fp = fopen("test.txt","w"); //1バイトのデータを6個(6バイト分)書き込む. fwrite(ch,1,6,fp); fclose(fp); //書きこまれているか確認 fp = fopen("test.txt","r"); fgets(ch,50,fp); //画面に出力して確認 printf("書き込まれた文字は→ %s\n",ch); fclose(fp); //ファイルの読み込み if((fp = fopen("test.txt","r")) == NULL){ printf("ファイルを開けませんでした");//ファイルがないときのエラー処理 } else{ char ch; while((ch = fgetc(fp)) != EOF){ //1文字だけをファイルの終わりまで読み続ける printf("一文字だけ読みこみ%c\n",ch); } fclose(fp); } // ファイルのオープン fp = fopen("test.txt","w"); // ファイルに書き込み fputc('h', fp); fwrite(ch,1,6,fp); fputs("ijkl",fp); // ファイルのクローズ fclose(fp); //ファイルの読み込み if((fp = fopen("test.txt","r")) == NULL){ printf("ファイルを開けませんでした");//ファイルがないときのエラー処理 } else{ fgets(buf,50,fp); printf("ファイルに書き込まれた文字列は→ %s\n",buf); fclose(fp); } return 0 }
以上が,授業のおさらいです.しっかりと復習をしておきましょう.
では,課題の考え方について解説したいと思います.
- 5組
1. このファイル document.txt に書かれた文章を,まずそのまま画面に表示し, その後に,同文章を構成するアルファベット,数字,記号,スペースなどの個数を表示せよ. なお,英文字は大文字と小文字は区別せずにカウントすること.
// 実行例 数値が正しいとは限らない 文章: Ubuntu is a Debian-based Linux operating system, with Unity as its default desktop environment. It is based on free software and named after the Southern African philosophy of ubuntu (literally, "human-ness"), which often is translated as "humanity towards others" or "the belief in a universal bond of sharing that connects all humanity". ........... 文字数カウント結果: a は 100 個ありました. b は 30 個ありました. c は 70 個ありました. d は 60 個ありました. e は 200 個ありました. ... " は 32個ありました. スペースは 100個ありました.
まずはfgetsを利用してEOFまで文字列を行ごとに読み込みましょう.そして読み込んだ行ごとの文字列を対象に,”文字と文字列”の実習課題2を参考にしながら,文字の出現頻度をカウントしましょう.そして最後に行毎にカウントしたそれぞれの文字の出現頻度を足しあわせましょう.
EOFまでファイル読み込みが達したかどうかを確認するには以下のコーディングを参考にしてください.
FILE* fp; . . . while(!feof(fp)){ . . . }
2. 以下のリンクからテキストファイルinputdata.txtをダウンロードせよ.
このファイルを読み込み,一行ごとの数値(5個のデータ)の平均値を行の最後に追加し,別のファイルに書き込むプログラムを作成せよ.
出力するファイル名は,outputdata.txt とする.
【ヒント】上記ファイルには,1行に5個の数値データが格納されている.今回は,データ個数が事前に分かっているとしてよい.
ファイル読み込みした数値をそれぞれの数値毎に格納する2次元配列を用意しましょう.ここまで課題をしっかりこなしてきた人であれば,行毎に平均値を算出することは簡単でしょう.
そして,fprintf()で順番にファイル読み込みした数値を出力するようにループを回し,その行の読み込んだ最後の一文字がファイル出力されたあとに平均値を出力し,最後に改行コードを出力する. . . . .というながれを繰り返せばOKです.
3. このファイルは test_result.csv 内には,各行に生徒の名前と 3科目のテストの点数がカンマ( , )区切りで記述されている.
このファイルの中身を読み取り,各生徒の合計点数を算出してその値が大きい順に並べてファイル test_rank.csv に出力するプログラムを作成せよ.
ヒント:fscanf関数を用いて1行分のデータを読み込むには,ファイル内のデータに合わせて書式指定文字列に,"%s,%d,%d,%d" を使用する. (test_rank.csvの各行に,名前と合計点をカンマ区切りで記し,最後の行に平均点を追加すること.)
// 出力ファイルの中身 Yuma,285 Alicia,276 Clarice,274 Jean,273 《中略》 Flora,214 Elena,206 Kate,165 average,247.13
基本的な流れは前問と同様です.ファイル読み込みとファイル出力の際には,しっかり名前と点数をカンマ区切りする点だけ注意しましょう.
4. 素数をファイル primes.txt に書き出せ.
(int 型の最大値である 2,000,000,000(20億)以下で良い.)
注意:出力ファイルのサイズは大きくなる可能性があるので,実行・確認が終わったら primes.txt は削除すること.
参考:下記のように,コンパイル時に -O2 オプションつけると実行速度の最適化が行われ,計算時間が短縮される場合がある.(短縮されない場合もある.)
c:\.windows2000> bcc32 -O2 152R??????-??-?.cpp
コンパイル時に-O2オプションをつけてみましょうということですね.ちなみに素数かどうか判定する単純なアルゴリズムをつかった関数は以下を参考にしてください.
bool PrimeJudge(int num) { if(num < 2){ return false; // 素数でない } for(int i = 2; i < num; i++){ if (num % i == 0){ return false; // 素数でない } } return true; // 素数である }
- 6組
1. 【as_document.txt】 に書かれた文章を読み込み,表示するプログラムを作成せよ. また,同文章を構成するアルファベット,数字,記号の個数も併せて表示せよ. なお,英文字は大文字と小文字は区別せずにカウントすること.
fgetsをつかって最後まで行を読み込みましょう.今度は読み込んだ文字列から1文字1文字カウントしていくプログラムをつくってください
2.【as_test_result.csv】 内には各行に生徒の名前と3科目のテストの点数がカンマ( , )区切りで記述されている(並びは名前順).このファイルの中身を読み取り,各生徒の合計点数を算出して、その値が大きい順に並べてファイルに出力するプログラムを作成せよ. なお,出力ファイル名はtest_rank.csvとし,各行に名前と合計点をカンマ区切りで記し, 最後の行に平均点を追加すること
カンマ区切りのファイルなので,fscanfを使って1つ1つ合っている型に読み込んでください.
あとは今までの課題同様に計算し大きい順にソートするだけです
3.以下の行列データ,
typedef double Matrix[4][4]; Matrix A = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
をメモリイメージそのままバイナリファイル 【as_matrix_image.bin】 に保存した. このデータを上記の行列変数に読み込み,画面に表示するプログラムを作れ.
バイナリファイルを開くときはfopen(filename,"rb")を使ってください
またバイナリファイルの読み込みにはfread(void* restrict ptr, size_t size,size_t nmemb, FILE * restrict stream)を使います
引数の意味としては
・ptr: 読み込む領域へのポインタ
・size: 要素 1 個あたりの大きさ
・nmemb: 要素の個数
・stream: ファイル
です
1. このファイル【as_lyrics.txt】 を読み込み,"*iller"が含まれる行だけを抜き出して 表示するプログラムを作成せよ(*は任意の文字)
fgets()を使って一行ずつ読み込み、"iller"の文字列が含まれるかを探索していきます。含まれていたらその行全体を表示させればokです。
1. このファイル【as_hex_words.txt】 には4桁区切りで16進数の数が格納されている. これを読み取って2桁ごとに区切り,ASCII文字として表示するプログラムを作成せよ.
読み込むときは16進の数値として読み込みましょう。読み込むことができれば、あとはL06データ型の分野の問題です。講義ページを見て復習しながら解いてみてください