PR

 連載11回目の今回は,ファイル処理について解説します。ファイルを扱えるようになると,実用的なプログラムを作成できるようになり,プログラミングの世界が広がります。なんだか難しい印象があるかもしれませんが,特別なことをいくつも覚える必要はありません。これまで勉強してきたことの延長線上で理解できます。なぜ,延長線上で理解できるかというと,C言語には「ストリーム」という様々な装置に対する入出力を統一的な方法で行うための仕組みが用意されているからです。

ストリーム入出力とは

 まずストリームとはなにかを解説するところから始めましょう(図1)。ストリーム入出力では,文字単位や行単位でファイルを読み書きする関数が直接ファイルをアクセスするのではなく,OSが設定したバッファ*1にアクセスして,バッファとの間で読み書きを行います。つまり,ストリーム入出力はバッファを使った入出力です。

図1●ストリームはOSが管理するバッファを通して,ファイルなどにアクセスする入出力方式
図1●ストリームはOSが管理するバッファを通して,ファイルなどにアクセスする入出力方式

 バッファの内容がすべて読み込まれ,バッファが空になったときは,OSが自動的にファイルの内容を読み込んでくれます。同様に書き込みによってバッファいっぱいになったときには,OSが自動的にファイルへ書き込んでくれます。このストリーム(流れ)により,プログラム側では1文字ずつ読み書きする処理であっても,ファイルへのアクセスが効率的に行われるわけです。

 実は,これまでもストリーム入出力の機能を利用してきました。それはディスプレイに文字を出力するprintf関数や,キーボードからの入力を変数に読み込むscanf関数です。キーボードという標準入力,ディスプレイという標準出力装置に対して,ストリーム入出力を行ってきたわけです(図2)。

図2●printfもscanfも実はストリーム入出力
図2●printfもscanfも実はストリーム入出力

 printf( )やscanf( )のほかにも,1文字入力を行うgetchar( )や1文字出力を行うputchar( ),1行入力のgets( ),1行出力のputs( )などのファイルを読み書きする関数があります。これらの関数はすべてストリームを利用します*2

ファイルのオープンとクローズ

図3●ファイルを利用するための手順
図3●ファイルを利用するための手順

 標準入力(キーボード)と標準出力(ディスプレイ)は,特に準備をしなくてもプログラムから利用できます。これらの装置はプログラムの開始時に開かれていると考えることができます。しかし,ハードディスクなどの補助記憶装置上でファイルを扱うには,準備と後片付けが必要になります。

 ファイルを使うには図3のような手順が必要です。まず,リスト1の(1)のように,

 FILE *fp;

としてファイル・ポインタを宣言します。ファイル・ポインタというと特殊なもののように感じられるかもしれませんが,たんなる構造体へのポインタです。Borland C++コンパイラ*3では,FILE構造体型はヘッダー・ファイルstdio.hの中でリスト2のように宣言されています。FILE構造体型は,ファイルの現在位置,バッファへのポインタ,ファイル・ステータスなどのファイル入出力に必要なメンバー変数で構成されています。

#include <stdio.h>

int main()
{
    FILE *fp; ―――――――――――――――――(1)
    fp=fopen("test.txt","w");
    if (fp == NULL) {
        puts("ファイルをオープンできません。");
        return 1;
    }
    fclose(fp);
    return 0;
}
リスト1●ファイルをオープンして,クローズするプログラム
typedef struct
{
        unsigned char   *curp;    /* Current active pointer     */
        unsigned char   *buffer;  /* Data transfer buffer       */
        int              level;   /* fill/empty level of buffer */
        int              bsize;   /* Buffer size                */
        unsigned short   istemp;  /* Temporary file indicator   */
        unsigned short   flags;   /* File status flags          */
        wchar_t          hold;    /* Ungetc char if no buffer   */
        char             fd;      /* File descriptor            */
        unsigned char    token;   /* Used for validity checking */
}       FILE;                     /* This is the FILE object    */
リスト2●stdio.hの中にあるFILE構造体の宣言