C言語入門 第14回 ファイル読み書き1(ファイル読み書きの基礎)




2014年10月より個人の方を対象に、Study C無料提供を開始しました。
C言語を勉強中の方は、学習・教育に最適なC言語インタープリタのStudy Cを使ってみてください(個人の方は無料です)。
大学・高専・高校などの教育機関での採用実績も多数あるロングセラー商品Study Cが、個人向けに無料提供を始めました。
インタープリタの手軽さに加え、ゲームや3Dタートルグラフィックで楽しく勉強したりと、C言語の学習を強力にサポートします。
ブロック崩しゲーム 3Dツリー クリスマスツリー
また、このようなボタンの用意されているページでは、掲載しているプログラムをStudy Cに直接ロードし実行したりすることができます。
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する
Study C無料利用についての詳細は、このページを参照してください。



1.ファイル使用の基礎

 今まで説明してきたプログラミング方法では、コンピュータの電源を切るとそれまで入力したデータが消えてしまいます。 これではコンピュータの利用価値が大きく損なわれてしまいます。 そこで、コンピュータには電源を切ってもデータを蓄えて置くことができる装置が用意されています。 このような装置の中で最も一般的なものがハードディスクです。 保存するデータはハードディスク内にファイルという形で蓄えられています。 Study Cで作ったプログラムのセーブも、プログラムというデータをハードディスクにファイルとして蓄えています。

 ファイル操作はちょうどノートの内容を読んだり、書き込むことに似ています。 まず、本棚から使用したいノートを持ってきて開きます。 そしてノートの内容を読み書きし、使い終わったらノートを閉じて本棚にしまいます。 実際のコンピュータでは、本棚がディスク、ノートがファイル、ノートに書かれている見出しがファイル名に相当します。 また、ノートを本棚から持ってきて開くことを「ファイルをオープンする」、本棚にしまうことを「ファイルをクローズする」といいます。

 C言語ではファイルを取り扱う代表的な関数が次の二つに分類されています。

(1)低水準入出力関数
(2)標準入出力関数/ストリーム関数

UNIXというOSで育ったC言語が色々な装置(デバイス)を制御するために(1)の低水準入出力関数を使用していました。 もちろん、ファイルの読み書きを行うことも可能です。 通常のファイル入出力を行うために使われる一般的な関数は、(2)の標準入出力関数/ストリーム関数です。 今回は、標準入出力関数/ストリーム関数の使用方法を説明します。

 標準入出力関数/ストリーム関数の主な(基本的な)関数を次に示します。

ファイルのオープンfopen()ファイルの読み書きを開始する
ファイルのクローズfclose()ファイルの読み書きを終了する
ファイルの内容を読むfgetc()1文字読み込み
fgets()1行読み込み
fread()n文字読み込み
ファイルに書き込むfputc()1文字書き込み
fputs()文字列の書き込み
fwrite()n文字書き込み


2.ファイルからの文字読み込み

 ファイル操作用の関数を使ってファイルの内容を画面に表示するプログラムを作って見ましょう。 ファイルのオープンからクローズまでの手順は次のように比較的パターン化されています。

#include <stdio.h>

main()
{
        FILE    *fp;

        fp = fopen( "ファイル名", "r" );
        if( fp == NULL ){
                ファイルオープンに失敗した
        }

        fgetc()関数などを使いファイルの内容を読み込む

        fclose( fp );
}

 fopen()関数の2番目のパラメータ"r"は読み込みのためのオープン(read open)を指示するものです。 NULL(および次の例でしようしているEOF)は第10回C言語入門で説明した#defineによって定義されたマクロ名です。 これらのマクロ定義は、Study Cがあらかじめ用意しているインクルードファイル stdio.h で定義されています(市販のCコンパイラにも stdio.h が用意されています)。 使用するコンパイラにもよりますが、0、-1といった数値が定義されていると考えておいてください。

 NULL や EOF を使わず0、-1のように直接数値を指定してもファイルを操作するプログラムを書くことができます。 しかし、Study C を卒業して他のCコンパイラを使うようになったとき、そのようなプログラムが動作する保証はありません。 いいかえれば、C言語ではNULLやEOFを使って書いているプログラムは、コンパイラが変わってもプログラムを修正せずにそのまま動作させることができます。

 FILE についてはtypedef、structという、これまでのC言語入門では説明されていない方法で定義されています。 ここでは、NULLやEOFと同様、defineで定義された型(char、intなど)のようなものと思っていてください。

#define FILEchar例えばchar型のような一種の型と思っておいてください
#define NULL0
#define EOF-1この定義は次の例で使っています

 次のプログラムは、readme.docというファイルの内容を読み込み画面に表示するプログラムです。

#include <stdio.h>

main()
{
        FILE    *fp;
        int     ch;

        fp = fopen( "readme.doc", "r" );
        if( fp == NULL ){
                printf( "File open error\n" );
                return;
        }
        for( ; ; ){
                c = fgetc( fp );
                if( c == EOF )
                        break;
                putchar( c );
        }
        fclose( fp );
}
Study Cにロードする Study Cにロードし編集する Study Cにロードし実行する ブラウザとの連携機能が使用可能なStudy Cのバージョンなどについて...

 このプログラムでは readme.doc という名前のファイルをオープンします。 ファイル readme.doc が存在しなければオープンすることができず、fp にはNULL (0)がセットされます。 ファイルが存在しないとFile open errorと表示してプログラムは終了します(ファイルが存在していてもアクセス権限など色々な理由でfopen()に失敗することがあります)。 ファイルが存在しない場合は、Study Cのsaveコマンドを使うなどしてファイルを作成して下さい。 fgetc()関数はオープンされたファイルの内容を先頭から1文字ずつ読み込んで変数cに代入していきます。 関数 fgetc()の返す値が EOF (-1)の場合、ファイルには読み込むデータが残っていないことを示します。



3.ファイルへの文字書き込み

 次にファイルへの書き込みを行います。ファイル書き込みも fopen()fclose() 関数を使用します。 ファイルからの読み込みでは fopen() 関数の2番目のパラメータで"r"を指定しましたが、書き込みでは"w"を指定します。 また、fgetc() 関数の代わりにファイルへの書き込みを行う fputc() 関数を使用します。

#include <stdio.h>

main()
{
        FILE    *fp;
        int     ch;

        fp = fopen( "output.txt", "w" );
        if( fp == NULL ){
                printf( "File open error\n" );
                return;
        }

        fputc( 'A', fp );
        fputc( 'B', fp );
        fputc( 'C', fp );
        fputc( '\n', fp );
        fputc( 'D', fp );
        fputc( 'E', fp );
        fputc( 'F', fp );

        fclose( fp );
}

 このプログラムでは output.txt という名前のファイルにABCDEFという文字を書き込みます(ABCとDEFの間は、改行されます)。 プログラムを実行したら、Study Cのコマンドモードで「type output.txt」と入力すると出力結果を表示することができます。 fputc() 関数の2番目のパラメータで出力する文字を指定します。fputc( '\n', fp ) は改行を出力します。


4.ファイルからの行読み込み

 ファイルの内容を読み込む場合、fgetc() 関数を使って1文字づつ読み込むより1行単位などまとめて読み込む方が便利だと思います。 行単位の読み込みは fgets() 関数を使用します。

#include <stdio.h>

main()
{
        int     ch;
        char    buff[200];

        fp = fopen( "readme.doc", "r" );
        if( fp == NULL ){
                printf( "File open error\n" );
                return;
        }
        for( ; ; ){
                if( fgets(buff, 200, fp) == NULL)
                        break;
                printf( "%s", buff );
        }
        fclose( fp );
}

 fgets() 関数は、ファイルから行の終わりかファイルの終わりまでを読み込み1番目のパラメータで指定した場所に格納します。 このプログラムでは、「char buff[200];」で宣言した変数に格納されます。2番目の変数では格納する場所のサイズ(バイト数)を指定します。 1行が200文字を超えていると上手く動作しませんが、ここで使用するファイルの1行は200文字を超えないものとします。 また、fgets() 関数はファイルの最後に到達した場合 NULL を返します(fgetc() 関数のEOFと異なります)。 変数 buff に読み込まれた文字列は printf() 関数で画面に表示しています。


5.ファイルへの文字列書き込み

 ファイルへの文字列単位での書き込みを行います。fputc() 関数の代わりに fgets() 関数を使用します。 fgets() 関数では、1番目のパラメータで文字の変わりに文字列を指定しています。

#include <stdio.h>

main()
{
        FILE    *fp;
        int     ch;

        fp = fopen( "output.txt", "w" );
        if( fp == NULL ){
                printf( "File open error\n" );
                return;
        }

        fputs( "1行目\n", fp );
        fputs( "2行目\n", fp );
        fputs( "3行目", fp );
        fputs( "前の書込で改行がないため同じ行", fp );

        fclose( fp );
}

 このプログラムでは output.txt という名前のファイルに3行の文字列を書き込みます。 プログラムを実行したら、Study Cのコマンドモードで「type output.txt」と入力すると出力結果を表示することができます。 fputs() 関数は4回呼び出していますがファイルには3行が書き込まれています。 fputs() 関数は行を出力する訳ではないので、行を分けたい場合は最初の2回の呼び出しのように文字列の最後に改行(\n)を指定します。