>> C言語入門トップに戻る

ファイルの読み書き

今回はファイルの読み書きについて説明します。
今までは黒い画面上で文字の出力をしているだけでしたが、
その内容をファイルに書き出したり、またファイルを読み込んで表示することも出来ます。
ファイルにはテキストファイル(文字がかかれたやつ)とバイナリファイル(音楽や動画ファイル)がありますが、
まずはテキストファイルの読み書きから説明します。
まず下記のコードを見てください。

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
	FILE *fp;

	fpos_t size;

	char buf[100];

	//test.txtのファイルを作成
	fp=fopen("test.txt","w");

	//ファイル作成失敗したらNULLポインタが返る
	if(fp!=NULL){
		fprintf(fp,"あいうえお");
		fclose(fp);
	}else{
		printf("ファイル作成失敗");
		return -1;
	}

	//読み込み
	fp=fopen("test.txt","r");

	//ファイルが無いとNULLが返る
	if(fp==NULL){
		return -1;
	}

	//ファイル読み込み
	fscanf(fp,"%s",buf);
	//表示
	printf("%s\n",buf);

	//ファイルサイズ取得
	//まずファイルの末尾までファイルポインタを移動
	fseek(fp,0,SEEK_END);
	//現在位置を取得。
	fgetpos(fp,&size);

	//ファイルの末尾位置=ファイルサイズなのでそのまま表示
	printf("ファイルサイズは%dです\n",size);
	
	//閉じる
	fclose(fp);
	
	return 0;
}

これを実行するとこうなります。

ファイルを読み込むには、fopen関数を使います。
fopen関数は実行すると、FILE型というポインタを返します。
第一引数には作成するファイル、または読み込むファイル名、
第二引数にはファイルにアクセスする際のオプションを指定します。
オプションには以下のものがあります。

r  → 読み出し専用
w → 書き込み専用
a → 追加書き込み専用
r+ → 読み込みと書き込み
w+ → 書き込みと読み込み
a+ → 読み込みと追加書き込み

rが読み込み、wが書き込み、aが追記書き込みです。
それぞれに+をつけると、書き込み読み込みの両方が可能になります。
なお、読み込み時にファイルが無かった場合はNULLが返ります。
ファイル作成時にファイルがあった場合は上書きされます。

コードを見てもらうと、まず最初に、fopen関数でtest.txtファイルを書き込み専用で作成しています。
その後、fprintf関数で文字をファイルに書き出しています。
これは第一引数に、FILE型のポインタを、第二引数に文字を指定します。
同じような関数で、fputs関数もあります。
これには第一引数に文字を、第二引数にファイルポインタを指定します。
書き込んだ後は、fclose関数でファイルを閉じています。
ファイルを読み書きした後はこの関数で必ず閉じてください。
この関数にはファイルポインタを指定するだけで結構です。

その次のコードでまたファイルを読み込み専用で読んでいます。
その後、fscanf関数でファイルを読み込んでいます。
第一引数にファイルポインタ、第二引数にformat文字列(%sとか%dとか)を、
第三引数に読み込んだ文字を書き込むバッファ(メモリ or 配列こと)のポインタを指定します。
今回は先程書き込んだ「あいうえお」という文字列を読み込んでいるので、
fscanfの第二引数は文字列を意味する%sを指定してます。
この関数はファイルに文字列があれば、その文字列があるところまで読み込むので、
第三引数に指定するバッファの容量には気をつけて使って下さい。

このfscanfに似た関数で、fgetsというのもあります。
この関数はファイルから一行読み込みます。
テキストファイルでの改行は目には見えませんが改行コードというものが入っています。
この関数はその改行コードまで読んでくれるというわけです。
さらに、読み込んだ文字列の最後にはNULL文字(\0)も付加してくれます。
第一引数には、文字を書き込むバッファ、第二引数には読み込む文字数、第三引数にはファイルポインタを指定します。
ちゃんと改行まで読むには第二引数に改行までの文字数よりも多い値を入力して下さい。
もちろんバッファはそれ以上の容量を確保したものを使って下さい。
上記のコードではfscanfで文字列を読み込んだあとprintfで表示しています。

最後に、fgetpos関数とfseek関数を説明します。
fgetpos関数とは、ファイルポインタがある現在位置を返します。
例えばfgetsで一行分読み込んだとします。
するとファイルポインタというのはその一行分のバイト数分その位置に移動しています。
このときにこの関数を実行すると、その位置をバイト数で返してくれるわけです。
つまり、ファイルの末尾にファイルポインタがある状態でこの関数を実行すると、
ファイルサイズが取得できることになります。

この関数は、第一引数にファイルポインタを、第二引数にfpos_tという型のポインタを指定します。
この第二引数のポインタに現在位置が入ったポインタが返されます。

ではファイルポインタをどうやって末尾に移動させるのかというと、
fseek関数を使います。
この関数は第一引数にファイルポインタ、第二引数に第三引数で指定した位置からのオフセット、
第三引数にファイルポインタを移動させる基準位置を示す定数を指定します。
第三引数の定数は以下の三つがあります。

SEEK_SET →ファイルの先頭
SEEK_CUR →ファイルの現在位置
SEEK_END →ファイルの末尾

この位置から、第二引数で指定した分のバイト数だけファイルポインタを移動させることができます。
例えば、ファイルポインタの先頭から5バイト進めた位置に移動させたい場合は、
fseek(fp,5,SEEK_SET);
となります。
今回は、
fseek(fp,0,SEEK_END);
となっているので、ファイルの末尾から0バイト移動させた位置、
つまり、ファイルの末尾にファイルポインタを移動させているという意味になります。
そしてこの状態で、fgetpos関数を使って、ファイルサイズを取得し、表示している、
という流れになっています。

以上が、テキストファイルのファイルのファイルの読み込み書き込みの説明です。

次にバイナリファイルの読み書きの説明ですが、
大きく変わることはありません。
バイナリファイルを開くには、fopen関数の第二引数のオプションの後ろにbをつけます。
例えば書き込みモードでバイナリファイルを作成する場合は、
fopen("test.txt","wb");
というようになります。

そしてファイルの読み書きは、fread関数とfwrite関数を使います。
fread関数は、第一引数にバッファ、第二引数に読み込むデータの型のサイズ、
第三引数にその型のデータの個数、第四引数にファイルポインタを指定します。
fwrite関数は、fread関数と一緒で、第二引数と第三引数の読み込むを書き込むと読み替えてくれれば大丈夫です。
fgetposとfseek関数も使えます。

ここで簡単にテキストファイルとバイナリファイルの読み書きの違いについて説明します。
それは基本的には改行コードの扱いだけです。
C言語では改行コードの扱いは\nで表されますが、
windowsでは、\r\nで表されます。
もしテキストモード(bをつけずに)で読み込んだ場合は、このwindowsの\r\nの改行コードを
C言語で扱えるように自動的に\nに変換して読み込んでくれます。
また、書き込む時も、\nの改行コードをwindows用に、\r\nとして書き出してくれます。
これがテキストモードです。

逆にバイナリモード(bをつける)というのは、ファイルをそのまま読みます。
つまり、改行コードなんか意識せずに読み込んでしまうので、
windowsの改行コード\r\nが何も変換されないまま、読み込みます。
書き出すときもC言語での改行\nをファイルに書き出したとしても、windows用に変換されず、
そのまま書き出されます。
これがバイナリモードです。

二つのモードの違いがわかりましたでしょうか?
たったこれだけの違いですが、今後バイナリデータを扱ってくるようになると役に立つと思いますので
しっかり覚えておきましょう。

次回は、役に立つ文字列関数について、いくつかご紹介します。


>> 【文字列系関数】に進む
>> C言語入門トップに戻る