苦しんで覚えるC言語

テキストファイルの読み書き


第1項:ファイルの取り扱い

今までは、入出力を行う場合、全て画面に表示してきました。
画面に表示すれば、結果がすぐにわかって便利だからです。
しかし、画面に表示された結果は、プログラムが終わると消えてしまいます。
また、膨大な量のデータを画面に表示するのは現実的ではありません。

この様な場合、ファイルにデータを保存するのが普通です。
ファイルとして保存されたデータは、ディスク上に保存されるので、
消えることはなく、コピーや再編集が容易です。

ここでは、C言語でファイルを読み書きする方法を説明します。

目次に戻る

第2項:ファイルの開閉

プログラムからファイルを操作する手順は、おおむね次のような順番で行われます。

ファイルを開く -> ファイルに読み書きする -> ファイルを閉じる
つまり、ファイル操作には、ファイルの開閉が必須となっています。
そこで、C言語には、ファイルを開閉する関数が用意されています。
開く関数が fopen関数、閉じる関数が fclose関数です。
この関数を使うには、stdio.h のインクルードが必要になります。
それぞれの関数の使い方は、次の通りになります。

FILE型のポインタ変数 = fopen(ファイル名,モード);
fclose(FILE型のポインタ変数);
ファイル名とは、その名の通りのファイル名です。
フルパスで指定することも、名前だけで指定することも出来ます。

モードとは、ファイルを開く目的を表す文字列のことです。
モードには、次の6種類の文字列の内どれか1つを指定します。
モード文字列目的
r読み込み。ファイルがない時は失敗。
r+読み書き。ファイルがない時は失敗。
w書き込み。ファイルがあっても空のファイルを作る。
w+読み書き。ファイルがあっても空のファイルを作る。
a追加書き込み。ファイルがない時は作る。
a+読み書き。ファイルがない時は作る。
FILE型とは聞き慣れない型ですか、その正体は構造体です。
fopen関数を実行すると、ファイル情報を持つFILE型へのポインタが返されます。
このポインタは、以後、開いたファイルの識別子として使うだけなので、
ポインタ特有の操作を行ったり、構造体の要素を使うことはありません。
今後、FILE型へのポインタ変数を、ファイルポインタと呼びます。

ここまで説明したことがわかれば、ファイルの開閉が出来ます。
次のプログラムは、test.txtと言う名前のファイルを書き込みのために開く例です。

#include <stdio.h>

int main(void)
{
	FILE *file;
	file = fopen("test.txt","w");
	fclose(file);
	return 0;
}
このプログラムを実行すると、test.txtという名前のファイルが作成されます。
今回は開いただけなので、当然中身は空っぽです。
fcloseの役割
一見、無意味なfopen関数ですが、ちゃんと役割があります。

WindowsやUnix(Linux)やMacなど、同時に複数のソフトが動く環境では、
もし、同じファイルを同時に2つのソフトで書き換えてしまうと、
どちらを反映すれば良いのかわからなくなってしまうので、
fopen関数で書き込みが出来るように開いたファイルには、
他のソフトで書き換えられないよう鍵をかけています。
fclose関数は鍵をはずして他のソフトから使えるようにします。

その他、ファイルを開いているときはメモリ内に保存し、
fclose関数が実行されたときに初めてディスクに書き込むことで、
高速化していることもあります。

目次に戻る

第3項:ファイルへの書き込み

ファイルへテキストを書き込む関数は、多くの種類が用意されています。
その中に、馴染みのprintf関数と良く似た、fprintf関数があります。
fprintf関数の使い方は、次の通りです。

fprintf(ファイルポインタ,書き込み文字列,変数・・・);
使い方は、ファイルポインタを指定すること以外、printf関数と全く同じですが、
指定した文字列は、画面ではなくファイルに書き込まれます。
次のプログラムは、test.txtファイルに Hello,world の文字列を書き込みます。

#include <stdio.h>

int main(void)
{
	FILE *file;
	file = fopen("test.txt","w");
	fprintf(file,"Hello,world");
	fclose(file);
	return 0;
}
このプログラムを実行すると、test.txtファイルの中身は次のようになります。
test.txtファイルは、実行ファイルと同じフォルダに作られます。
 testtxt
Hello,world
printf関数と同じように、変数の値を書き込むことも出来ます。
次のプログラムは、test.txtファイルに変数iの値を書き込みます。

#include <stdio.h>

int main(void)
{
	int i = 100;
	FILE *file;
	file = fopen("test.txt","w");
	fprintf(file,"%d",i);
	fclose(file);
	return 0;
}
このプログラムを実行すると、test.txtファイルの中身は次のようになります。

100
読み込みと追加の場合
読み込みモードで開いた場合、書き込み用の関数を使っても何も起きません。
追加モードで開いた場合、元のファイルの最後にデータが追加されます。

目次に戻る

第4項:ファイルからの読み込み

ファイルのテキストを読み込む関数にも多くの種類がありますが、
馴染みのscanf関数に似たfscanf関数があります。
先頭でファイルポインタを指定することを除き使い方はscanf関数と同じです。

scanf関数はキーボートから読み込むため、実行すると入力待ちになりましたが、
fscanf関数では、ファイルのテキストを先頭から読み込みます。
次のプログラムは、test.txtファイルから先頭の数字を読み込んで表示します。

#include <stdio.h>

int main(void)
{
	int i;
	FILE *file;
	file = fopen("test.txt","r");
	fscanf(file,"%d",&i);
	fclose(file);
	printf("%d\n",i);
	return 0;
}
このプログラムの実行結果は、test.txtファイルの中身によって異なります。
test.txtファイルの中身が次の通りだった場合、実行結果は次の通りになります。
test.txt
100

100
上の例のように%d指定子を使用した場合、数字以外のテキストは無視されるので、
test.txtファイルの中身が次の通りだった場合、実行結果は次の通りになります。
test.txt
test100

100
文字列の入力に使用する%s指定子を使用すれば文字列全体を読み込めます。
しかし、スペースなどが含まれる場合にはそこまでしか読み込まれません。
test.txt
test100

test100
また、複数の数値をカンマ(,)で区切って並べてやれば、
複数の変数を読み込むことも可能です。

#include <stdio.h>

int main(void)
{
	int i,j;
	FILE *file;
	file = fopen("test.txt","r");
	fscanf(file,"%d,%d",&i,&j);
	fclose(file);
	printf("i = %d : j = %d\n",i,j);
	return 0;
}
test.txt
23,56

i = 23 : j = 56
この様にカンマ(,)で区切って数値や文字列を並べたファイルをCSV形式と呼び、
エクセルなどの表計算ソフトで扱える汎用的なファイル形式として知られています。

目次に戻る