第37回
ファイルの扱い(2)~ファイル操作の実例

FILE構造体の中身

Cでは、オープンしたファイルをFILE型の構造体(FILE構造体)へのポインタを介してアクセスします。FILE構造体の中身を覗いてみましょう。

ファイルポインタとFILE構造体

fopen関数でファイルをオープンするとメモリ上にFILE型の構造体が生成され、fopen関数はそれへのポインタを返します。これを「ファイルポインタ(file pointer)」と呼びます。

プログラムでは、fopen関数を呼び出す前にFILE型構造体のポインタを宣言し、fopen関数の戻り値をこれに代入します。

FILE *fp;

変数名の“fp”は“file pointer”の略で、慣習としてこの名前を使います。しかし、これは決まりではないので、違う変数名でも構いません。

このとき宣言するのはFILE型のポインタであって、その実体ではありません。FILE構造体の実体は、fopen関数が生成します。

オープンに成功した後は、このファイルポインタを引数として前回紹介したファイル操作関数を呼び出し、ファイルを操作します。

FILE構造体のメンバ

ファイル操作関数は、ファイルポインタを通じてFILE構造体のメンバを参照し、ファイルを操作します。ファイル操作関数を使えば、ファイルに関するほとんどすべての操作を実行できるため、プログラマーが直接FILE構造体をアクセスする必要はありません。

しかし、FILE構造体のメンバを確認すれば、Cがどのようにファイルを扱っているのかを知ることができます。

FILE構造体はstdio.hで定義されており、その構成は処理系によって微妙に異なっています。リスト1はLSI-Cのものです。

リスト1:FILE構造体の定義(LSI-Cの場合)
typedef struct {
char mode;
char *ptr;
int rcount;
int wcount;
char *base;
unsigned bufsiz;
int fd;
char smallbuf[1];
} FILE;

主なメンバの役割

すべてのメンバの役割が明確に解説されている訳ではないので、以下に主なメンバの役割を掲げておきます。

mode : オープンしたファイルのアクセスモード(r,w,r/w)
ptr : 読み書きしている位置(先頭からのバイト数) ※1
count : ptrの示す読み書き位置からファイル終端までのバイト数
base : メモリ上に確保したファイルアクセス用バッファの先頭位置
bufsize : ファイルアクセス用バッファのサイズ
fd : ファイルディスクリプタ(標準入力、標準出力、標準エラー出力などを示す番号)

他の処理系でも、メンバの名前などはそれぞれ異なりますが、主なメンバとその役割はおおよそ共通しています。

たとえば、ファイルを先頭から1バイトずつ読み取っていくと、ptrの値はその都度1ずつ増加されます。ファイルの終端からデータを追加モードで書き込めば、ptrの値は書き込んだデータのバイト数分増加されます。

この値を0にすれば読み書きの位置は先頭に位置付けられますし、10減少すれば読み書きの位置を10バイト戻すことになります。リスト2のようにすれば、ファイル“abc.txt”の先頭から10文字を3回繰り返して縦に表示できます ※2

リスト2:ファイルの先頭から10文字を3回縦に出力する
#include <stdio.h>

int main(void)
{
	int i,j;
	FILE *fp;
	int c;

	fp = fopen("abc.txt", "r");

	for (i=0; i<3; i++) {
	  for (j=0; j<10; j++) {
	  c = fgetc(fp);
	  putchar(c);
	  putchar('\n');
	  }
	  fp->ptr -= 10;
	}
	return (0);
}

この読み書き位置を示す変数を「ファイルポインタ」と呼んでいる処理系もあります。混同を避けるため、本コラムでは『FILE構造体を示すポインタ』を「ファイルポインタ」と呼びます
プログラムとしての意味はほとんどないので、このプログラムはサンプルに含めていません