[前へ]   [目次へ]   [次へ]

テキストファイルの読み込み(C/C++)


今回はテキストファイルの読み込みについてです。
前回に引き続き、C標準ライブラリで解説を行います。

さて、テキストファイルからの読み込みについての解説の前に、
「改行コード」というものについて解説しておきます。

「改行コード」というのはテキストファイルで改行を表すコードで、
「CRLF」(主にWindowsで使用)、「LF」(主にLinux系で使用)、「CR」の三種類が主です。
テキストエディタでは通常、開いた時にコードを自動識別して解釈していますが、
Windows標準のメモ帳は常にCRLFとして解釈します。
そのため、テキストエディタだと正常に開けるのに
メモ帳で開くと改行が化けているというファイルがしばしばあります。

ここで言う「CR」と「LF」はそれぞれ ASCIIコード のCR(0x0D)とLF(0x0A)のことで、
「CRLF」はこの二文字が連続していることを意味しています。

テキストファイルをテキストモードで開いた場合は、
ファイル上の「CRLF」が改行文字一個に置き換えて読み込まれ、
改行文字一個が「CRLF」に置き換えて書き込まれます。

プログラム上の改行文字は「LF」と同じです。
そのため、実はテキストモードでファイルを開くだけで「CRLF」と「LF」の両方のテキストファイルを読み込めます。
また、バイナリモードで開いたファイルにテキストだけを書き込むと「LF」のファイルが出来、
テキストモードで開いたファイルにテキストを書き込むと「CRLF」のファイルが出来ます。

「CR」だけは特別に処理が必要なのですが、
Windows上で「CR」記述のファイルは滅多に見ないのでテキストエディタでもない限りは無視でいいかと思います。


それではテキストファイルの読み込みについてです。
ファイル制御では、ハンドルごとに「操作位置」というものが存在します。
ファイルは概念上一直線にバイトが並んでいる扱いになっていて、
「操作位置」とは次に行うファイルアクセスがファイルの何バイト目から行われるのかということを示します。
原則として読み書きともに実行するたびに「操作位置」は更新され、
同じ関数を繰り返し呼び出しても結果は同じにはなりません。

テキストモードでファイルを開いた場合はテキスト読み取りの関数を使わなければならないことになっています。
なので、バイナリ読み取りの fread を除く、 fgetc と fgets と fscanf が対象となります。

●fgetc

プロトタイプ宣言:
int fgetc(FILE *stream)

ハンドル stream が示すファイルから半角1文字を読み取り、その値を返します。
全角文字の場合は1バイト分だけ返されるので注意します。
読み込めなかった場合やエラーが発生した場合は EOF を返します。
読み込みに成功すると操作位置が1バイト進みます。

戻り値:読み取られた文字コードか、読み込めないまたはエラーが発生した場合は EOF を返します。

引数:
FILE* stream :読み取り対象のファイルを示すハンドル。

使用例:
注:カレントディレクトリに「ABCDE」と書かれたファイル「085sample.txt」がある前提です。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
#include <stdio.h>

int main(void){
   FILE *fp;
   
int n;
   fp=fopen(
"085sample.txt","r");
   
while((n=fgetc(fp))!=EOF){
      printf(
"%c",n);
   }
   fclose(fp);
   getchar();
   
return 0;
実行結果:
ABCDE


●fgets

プロトタイプ宣言:
char* fgets(char *outputstr,int count,FILE *stream)

以前にも解説したことがありますが、本来はこっちの用途です。
ファイル読み込みでも最も使い勝手がいいので出番も多いです。

ハンドル stream が示すファイルから count-1 バイト、
またはファイルの終端まで、
または改行文字が読み込まれるまでの条件の中から、
もっとも少ないバイト数になるバイト数を読み込みます。

と真面目に書くとややこしいのですが、
ようするに一行読み込むのが原則で、 count-1 バイトを読み込み上限、終端に達したらそこまでということです。
なお、改行文字が読み込まれた場合は outputstr の最後に付きます。

読み込みに成功すると読み取ったバイト数分操作位置が進みます。
改行文字で読み込みを終了した場合は改行文字の次のバイトが操作位置に設定されます。

戻り値:読み込みに成功した場合は outputstr がそのまま返されます。
      読み込めなかった場合やエラーが発生した場合は NULL が返されます。

引数:
char *outputstr :[出力]読み込んだ文字列を格納する配列へのポインタ(絶対ID)。
int count : outputstr に書き込むことが出来る上限バイト数。
FILE *stream :読み取り対象のファイルを示すハンドル。

注意事項:
outputstr が示す配列が count バイト以上の大きさであることは呼び出し元が保証する必要があります。

使用例:
注:カレントディレクトリに「A\nBC\nDE」(\nは改行)と書かれたファイル「085sample2.txt」がある前提です。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
#include <stdio.h>

int main(void){
   FILE *fp;
   
char buf[1024]="";
   fp=fopen(
"085sample2.txt","r");
   
while(fgets(buf,1023,fp)!=NULL){
      puts(buf);
   }
   fclose(fp);
   getchar();
   
return 0;
実行結果:
A
BC
DE



●fscanf

プロトタイプ宣言:
int fscanf(FILE *stream,const char *format,...)

以前解説した sscanf の第一引数がファイルハンドルに変わっただけの関数です。
ファイルから必要なだけ読み出します。
仕様は sscanf を参照してください。
実行後の操作位置は指定されたうち成功した部分だけ進められます。
実行後の操作位置が紛らわしいため、 fgets と sscanf を組み合わせた方が扱いやすいです。
なのでこれ以上は説明しません(笑)


ということで、三個の関数の仕様を見てきましたが、私は fgets 関数を主に使うのをお勧めします。
なので、先ほどの fgets 関数のサンプルについてもう少し細かく見ていきます。

注:カレントディレクトリに「A\nBC\nDE」(\nは改行)と書かれたファイル「085sample2.txt」がある前提です。
<  1>
<  2>
<  3>
<  4>
<  5>
<  6>
<  7>
<  8>
<  9>
< 10>
< 11>
< 12>
< 13>
#include <stdio.h>

int main(void){
   FILE *fp;
   
char buf[1024]="";
   fp=fopen(
"085sample2.txt","r");//(1)
   
while(fgets(buf,1023,fp)!=NULL){//(2)
      
printf("%s",buf);//(3)
   }
   fclose(fp);
   getchar();
   
return 0;
実行結果:
A
BC
DE


(1)6行目では、カレントディレクトリにある「085sample2.txt」をテキスト読み取りモードで開いています。
サンプルということでエラー処理は省略しています。
実際に使う場合はちゃんと結果が NULL かチェックするようにしてください。

(2)7行目ですが、これは「 fgets が NULL 以外を返す限り続く」ループ条件となります。
fgets 関数は一行単位で読み出し、読み出したバイト数分操作位置を進めるので、
こうするとテキストファイルの一行ごとに実行するループとなります。
(一行が読み取り上限バイト数以下である必要はあります)
そして、ファイルの終端に到達した状態で fgets を呼び出しても読み込むことができないので、
そうなると fgets は NULL を返し、このループは終了します。

(3)8行目で fgets によって読み込んだ文字列を表示しているわけですが、
上記の通り一行単位で処理されるので、この行は今回の条件だと3回実行されます。
今回の場合1回目が "A\n" 、2回目が "BC\n" 、3回目が "DE" が出力されることになります。

fgets を用いた処理は、このような形でループを組んで行うことが多くなります。
読み取った文字列をどのように使うかは処理次第ですが、そこから先は今までの文字列処理と同じことになります。

これで単語当てゲームLv3に必要な要素が揃いました。
次回は単語当てゲームLv2を単語当てゲームLv3に改造していく予定です。

[前へ]   [目次へ]   [次へ]

プログラミング講座 総合目次

最終更新 2011/01/01