カテゴリー
C

C(Step3-1)

ファイルの入出力

ここでは、C言語では、どのようにしてファイルを操作し、保存・読み込みを行えるようにすればよいか説明していきます。

コンピュータにおけるファイルの種類

コンピュータ上のファイルは大きく分けて、テキストファイルとバイナリファイルの2種類に分類されます。ここでは、扱いが簡単なテキストファイルについて詳しく説明していきます。

テキストファイルとは、エディタなどで、そのファイルを開いたときに文字や記号が人間にわかるように記述されているファイルです。人の目に見える文字や記号の他にも「改行」「スペース」など見えない記号が書かれてることがあります。取り扱うときは、これらの「改行」や「スペース」などの記号も1文字として取り扱います。さらに日本語の1文字は2文字として取り扱わなくてはいけません。

ファイルにおける文字

全角文字が半角文字2文字分であることはC言語だけでなく、コンピュータで日本語を扱う時の一般的規則です。

ファイルを利用してのデータ入力

大量のデータをプログラムに入力しなくてはならない場合、どのようにファイルを利用してデータを入力できるか見ていきます。

例題:野球選手10人の打者の成績を評価するために1塁打1ポイント、2塁打2ポイント、3塁打3ポイント、ホームラン4ポイントとして過去30打席の成績をもとに得点を計算する。そこで、10人それぞれの打席の結果をポイントで入力し、10人の全打席のポイント数と合計した成績を表示するプログラムを作成する。

ここで、どのようにプログラムを作成するかと考え、アルゴリズムを考えます。

  • 30打席のデータをまとめて、1次元配列にする
  • さらに10人のデータがあるので、1次元配列をまとめて2次元配列にする

入力するデータをテキストファイルに

膨大な得点を手入力で入力するわけにはいかないので、入力するデータをあらかじめテキストファイルに入れておき、プログラムはこのテキストファイルからデータを読み込むようにすれば、データは何度でも使えますし、入力の手間を省けます。

入力するデータは以下のようにテキストファイルとして作って置くことにします。それぞれの行には整数値しか記入しません。(空白もありません)

選手の得点データ

テキストファイルを利用してプログラムに渡すようにしたプログラムを次に考えていきます。

#include <stdio.h>

int main(){
    int point[10][30];
    int total[10];
    int i, j;
    FILE *FP; //①ファイルを扱うための変数宣言

    /*ファイルを読み込み可能状態にする*/
    FP = fopen("data1.text", "r"); //②用意してあるテキストファイルを読み込み可にする
    
    /*ポイントの入力*/
    for(j=0; j<10; j++){
        for(i=0; i<30; i++){
            printf("背番号%2dの%d打席目のポイント入力\n", j, i+1);
            fscanf(FP, "%d", &point[i][j]); //③テキストファイルからデータを読み込む
        }
    }

    /*ファイルの使用を終了する*/
    fclose(FP);

    /*合計得点の表示*/
    for(j=0; j < 10; j++){
        total[j] = 0;
        for(i=0; i<30; i++){
            total[j] = total[j] + point[j][i];
        }
    }

    /*結果の表示*/
    printf("----結果----\n");
    for(i=0; i< 30; i++){
        for(j=0; j<10; j++){
            printf("%3d", point[j][i]);
        }
        printf("\n");
    }
    printf("---|---|---|---|---|---|---|---|---|---|\n");
    for(j=0; j<10; j++){
        printf("%3d", total[j]);
    }
    return(0);   
}
①ファイルを扱うための変数宣言

この部分は、変数宣言になります。ファイルを扱うためにはFILE(大文字表記)という型の変数を用意します。ただし、「*」が名前の前につきます。

■ファイルポインタの宣言
FILE *変数名;

C言語では、このように「*」をつけた変数をポインタ変数といい、FILE型のものはファイルポインタ(file pointer)と呼びます。これは、ファイルを操作しているときに、今ファイルのどこを読み込んでいるのかを示し、その場所を保存しておくポインタ型の変数です。

②ファイルのオープン

この部分は、ファイルのオープンと呼ばれる処理で、C言語でファイル操作するときには必須の部分です。fopen()という関数を使います。

■ファイルのオープン
・ファイルを読み込み可能にする
・ファイルポインタ(ファイルのどこを見ているか)をファイルの先頭で初期化する

ファイルポインタ = fopen("ファイル名", "r");
③ファイルからデータを読み込む

ここでは、fscanf()が出てきました。キーボードからのデータ入力を扱うのが、scanf()であるのに対して、ファイルから読み込むのがfscanf()になります。使い方は似ていて、違いは、はじめの引数にファイルポインタが加えられているだけです。

④ファイルのクローズ

この部分は、ファイルのクローズと呼ばれる部分で、ファイルをオープンして使用した後は必ず必要な処理です。fclose()という関数を使います。ファイルのクローズを忘れても実行できることがありますが、コンピュータ上の他のファイルを破壊したり、実行に異常がある場合もあるので、記述しておきましょう。

ファイルへのデータ出力

次に「ファイルに結果を出力」を例題を通して説明していきます。

例題:サッカーチームA、Bの10試合の対戦結果を入力すると、得点をグラフで表示するプログラムを作成する。

プログラムに起こすと以下のようになります。

#include <stdio.h>

int main(){
    int score[10][2];
    int i, j;
    FILE *FP; //①ファイルポインタの宣言

    /*得点結果の入力*/
    for(i=0; i<10; i++){
        printf("A対Bの第%d試合結果を数字2つで入力してください\n", i+1);
        scanf("%d %d", &score[i][0], &score[i][1]);
    }

    /*②ファイル書き込み可能状態にする*/
    FP = fopen("result.text", "w");

    /*③結果表示*/
    fprintf(FP, "----A----|----B----\n");
    for(i=0; i<10; i++){
        for(j=0; j<(10-score[i][0]); j++){
            fprintf(FP, " ");
        }
        for(j=0; j<score[i][0]; j++){
            fprintf(FP, "*");
        }
        fprintf(FP, "|");
        for(j=0; j<score[i][1]; j++){
            fprintf(FP, "*");
        }
        fprintf(FP, "\n");
    }
    fclose(FP); //④
    return(0);
}

このプログラムを実行し、対戦結果の数字を入力し終えても画面には何も表示されません。しかし、「result.txt」というファイルが作られ、ファイル内にぐらふが書かれていることがわかります。

②以外の部分は、前のプログラムと同じ処理を行います。ファイルのオープンのみ異なります。

■ファイルのオープン
・ファイルを書き込み可能にする
・ファイルポインタをファイルの先頭で初期化する

ファイルポインタ = fopen("ファイル名", "w");

ファイルからの読み込み処理では、readの1文字をとって「r」、ファイルへの書き込みはwriteの1文字をとって「w」となっています。

実用的なファイルのオープン方法

ユーザーにとってより使いやすいプログラムを提供するには、エラー処理も大切になります。エラー処理の第一歩として「ファイルからデータを読み込もうとしたのにそのファイルが存在しなかった」という場合に、「ファイルが開けません」というメッセージを表示してみましょう。

#include <stdio.h>

int main()
{
    FILE *FP;
    
    /*エラー処理を含むファイルのオープン*/
    if((FP = fopen("file.txt", "r")) == NULL){
        printf("ファイルが開けません\n");
        return(1);
    }

    /*ファイルが開けたときのみ実行される*/
    printf("ファイルが開けました\n");
    /*ファイルクローズ*/
    fclose(FP);
    
    return(0);
}

このサンプルを実行すると、ファイルが存在しなければ、「ファイルが存開けません」存在すれば、「ファイルが開けました」と表示します。ファイルが開けない時もプログラムをコントロールできます。

ファイルの利用方法の詳細

ここまでのファイルの使い方についてまとめておきます。

ファイルを操作できる状態、操作を終える
■fopen、fcloseの使い方
if((FP = fopen("file.txt", "X")) == NULL){ 
        [ファイルを開けない時の処理];
        return(1); 
} 

[ファイルを利用した様々な処理];

fclose([ファイルポインタ]);
  • ファイルポインタとは「FILE *変数名;」として変数宣言された変数を意味する
  • ファイル名にはディレクトリ名を含めることができる
  • Xには、どのようにファイルをオープンするか決める文字が入る
「r」…ファイルの先頭から読み込むとき
「w」…ファイルの先頭から書き込むとき
「a」…現在あるファイルの最後から書き込むとき
  • ファイルをオープンしたら、必ずファイルのクローズをする。ただし、開くのに失敗したときはいらない
ファイルから読み込む、書き込む
■fscanf()の使い方

fscanf([ファイルポインタ], "XXXXXX", Y1, ..., \n);
  • ファイルポインタとは「FILE *変数名;」として変数宣言された変数を意味する
  • XXXXXには、読み込みたい値の書式を記述する
  • 読み込みたい値の書式には、printf()で利用した%dなどの変換仕様を用いる
  • Yには、変数のポインタ(コンピュータ上で変数が用意されている場所の情報)を記述する。ここまでに説明した変数に値を読み込む場合には、変数名の先頭に&をつけたものを記述する
■fprintf()の使い方

fprint([ファイルポインタ], "XXXXXX", Y1, ..., \n);
  • ファイルポインタとは「FILE *変数名;」として変数宣言された変数を意味する
  • XXXXXには、書き込みたい値の書式を記述する。ここに文字や数値をそのまま記述すれば、それがファイルポに書き込まれる
  • 変数を書き込むときは、書き込みたい値の書式に、printf()で利用した%dなどの変換指定を用い、Yには変数を記述する