14.データ・ファイル

 

 14.1 データ・ファイル
 私たちが,種々のアプリケーション・ソフトウェア(アプリ)を使うとき,殆どのアプリには,何らかのデータを保存する機能が付いています.例えば,ワープロソフトの文書保存機能,表計算ソフトの表やグラフなどの保存機能,.,.数えあげればきりがありません.
 このように,アプリケーションで作成した文書データ,計算データ,画像データ,音楽のデータ...などは,1まとまりのファイルという形で記憶装置に保存することができます.このようにアプリで作成したデータの記録されたファイルをデータファイルと呼びます.

 私たちが作成するプログラムにも,データ・ファイルを作成したり,既存のデータ・ファイルを読み込んだりする機能を組み込むことができます.それができれば,プログラムの計算結果などを保存することができるようになるわけです.ここでは,プログラム中からファイルを作成したり,既存のファイルを読み込んだりするための文法を紹介します.


※よく,○○ファイルということばを聞くと思いますが,
ファイルは,いろんな観点から分類できます.
分類例:
  1)プログラムファイルとデータファイル
  2)テキスト・ファイルとバイナリー・ファイル
  3)シーケンシャル・ファイルとランダム・ファイル
  4)画像ファイル,文書ファイル,...
  5)複数のデータ・ファイルで構成されるデータベースでの役割別の分類
  6)その他,...いろいろ...

C言語の勉強上,基本的な分類は2)と3)です.



 

 14.2 ファイルとファイル名
 データをファイルに保存するときは,ファイルに名前をつけます.Widowsでは,ファイル名は次のような形をしています.
      abcdef.xyz
ここで,abcdefの部分をベース名(base name)xyzの部分を拡張子(extension)と呼びます.

ファイル名は,それを作成するひとが勝手に決めればよいわけですが,一般的に,拡張子には,そのファイルを作成したアプリケーション特有の名前を付けます.下記に一例をあげておきます.
   ・abcdef.doc     WORDの文書ファイル
   ・abcdef.xls     EXCELの表やグラフのファイル
   ・abcdef.c      C言語のソースファイル
   ・abcdef.cpp     C++のソースファイル
   ・abcdef.bmp     ビットマップ形式の画像ファイル
   ・abcdef.jpg     JPEG形式で圧縮した画像ファイル
   ・abcdef.gif     GIF形式で圧縮した画像ファイル
   ・abcdef.html     HTMLで記述したホームページファイル
   ・abcdef.txt     エディタで作成したテキストファイル
   ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・
   ・abcdef.exe     Windowsの実行可能ファイル(これはプログラムファイル)















 14.3 ファイルを扱うための予備知識

 ファイルを作成する前に,予備知識を整理しておきましょう.
ファイルを保存するための装置の話です.私たちの使用するPCには,フロッピーディスク・ドライブ,ハードディスク,MOドライブ,CD−ROMドライブなどの外部記憶装置が付属しているのが一般的です.データファイルは,これらの装置に(あるいはそれらの装置を使って記憶メディアに)保存します.

 通常,1個(枚)のメディアには,複数個のファイルを保存することが出来ます.ハードディスクなどは何万個ものファイルを保存できます.多数のファイルを1個(枚)のメディアに保存すると,目的のファイルを捜し出すのが大変なので,フォルダー(あるいはディレクトリー)を作成し,ファイルをグループごとに分類,整理し保存します.

 したがって,記憶メディアに保存したファイルを捜し出したり,保存したりするには,
   1)記憶装置名(どの記憶装置の)
   2)フォルダー名(どのフォルダーの)
   3)ファイル名(どのファイル)
を指定して初めて,読み込みや保存の作業ができるということになります.
 例えば,1個のファイルを読み込むと込むときは,次のように書いてファイルへのパスとファイル名とを指定しなければなりません.
    C:¥フォルダー名¥ファイル名
    A:¥フォルダー名¥ファイル名

ここで説明したことがらは,ワープロソフトなどのアプリを使った経験があれば,すでに理解済みだと思います.
ついでにいいますと,DOS/Vマシンでは,外部記憶装置には,(Windowsが決める)アルファベットの名前が割り当てられています.その中で基本的なドライブは名は下記の2つです.
  C ドライブ(Windowsのインストールされたハードディスク)
  A ドライブ(フロッピードライブ)
その他のドライブについても,自動的に(Windowsが決める)アルファベット名が割り当てられ,それをドライブの識別に使います.


 14.4 ファイルを作成してみよう

 では,ファイルを作成してみましょう
プログラム例14.2.1は,変数a,bに記憶された2数の和を計算しa,bの内容と和をディスプレイに表示すると共に,ファイルに書き込むプログラムです.
 実行する前に,フォルダーを作っておきましょう.ここでは,Cドライブにdataというホルダーを作ったものと仮定して,話を進めます.

 簡単なプログラムですが,説明することが結構あります.まず,ファイルを作成の過程を覚えるのが最初です.
ファイルを作成するには,
   1)ファイルを開く
   2)ファイルにデータを書き込む
   3)ファイルを閉じる
の3つの操作をしなければなりません.初心者は,「ファイルを閉じる」という操作を忘れがちですが,それを忘れたらファイルは作成されず,時間をかけて書き込んだデータ全てが無駄になってしまいます.


 プログラム例 14.4.1  実行結果
#include <stdio.h>

void main(void){
  int a, b, c;
  FILE *fp; /* ファイルポインターの宣言 */

  a = 3; b = 5; c = a + b;   
  /* 操作1:ファイルを開く(作成する)*/
  fp = fopen("c:\\data\\abc.txt","w");

    printf("%5d,%5d,%5d\n", a, b, c);

    /* 操作2:ファイルにデータを書き込む */
    fprintf(fp,"%5d,%5d,%5d\n",a, b, c);

  /* 操作3:ファイルを閉じる */
  fclose(fp);
}
    3,    5,    8


 では,ファイルを作成するために使用される一連の関数をみてみましょう.

FILE *fopen( const char *filename, const char *mode );filename で指定されたファイルを開きます.戻り値はファイルポインターを返す.失敗すればNULLを返す.
int fclose(FILE *filepointer ); ファイルを閉じる.成功すれば0を返す.

それぞれの関数の使い方は,次の通りです.

   fp=fopen("c:\\data\\abc.txt", "w");
 この関数は,ファイルへのパスやファイル名を指定してファイルを開きますが,同時にファイルモード,すなわち,ファイルをデータを書き込むために開くのか,読み込むために開くのかを指定します.ここではファイルをデータを書き込むために開くので,"w"(write)を指定します.この関数の実行結果は,ファイルポインター,fpで受け取りますが,ファイルポインターには,少なくとも,ファイルを特定する情報となるパス名を含むファイル名やファイルモードが記憶されます.したがって,一度ファイルを開いた後は,ここで開いたファイルを特定するのにfpを使うことができるようになります.

 ファイルにデータを書き込む関数には,複数のライブラリー関数がありますが,ここでは,
   fprintf(fp,"%5d,%5d,%5d\n", a, b, c);
を使っています.fprintf()は,printf()のファイルバージョンと考えてください.ただし,引数として,ファイルを指定するためのファイルポインターが追加されています.

 ファイルにデータを書き終えたら,ファイルを閉じます.
   fclose(fp);
もちろん,引数のfpは,閉じるファイルを指定するためのファイルポインターです.


※C言語のプログラム中では,文字'\'は,'\\'と書いてエスケープシーケンスとして表現します.



 14.5 作成されたファイルを確認する

 プログラム例14.2.1で作成したファイルはテキストファイルとして作成されます.
これは,テキストエディタ「メモ帳」で開き,内容を確認することができます.メモ帳で読みこんだ結果を実行結果14.3.1に示しておきました.実行結果14.2.2のprintf()分による実行結果と比較してみてください.
このようにテキストエディタでファイルを読み込むことができると言うことを知っていれば,この後,いろんな応用が考えられます.



また,Windowsの「コマンドプロンプト」の窓で確認することも出来ますね.
この場合,「コマンドプロンプト」の窓で,
   c:\>dir c:\data
と入力すれば,フォルダーdata中のファイル名のリストが表示され,
   c:\>type c:\data\abc.txt
と入力すれば,ファイルabc.txtのファイルの内容が表示されます.







 14.6 既存のファイルのデータを読み込む

 こんどは,作成済みのデータファイルからデータを読み込む手順を説明します.プログラム例14.4.1に例を示します.
 データ読み込みの場合,ファイルを開くとき,モードを"r"(read)とします.
   fp = fopen("c:\\data\\abc.txt","r");
ファイルにデータを書き込むときにはfprintf()関数を使いましたが,データを読み込むときはfscanf()関数を使用します.
   fscanf(fp,"%5d,%5d,%5d\n",&a,&b,&c);
この関数で,読み込んだデータは,変数a,b,cに代入されます.すなわち,読み込んだデータを代入する変数のアドレスを引数として渡せば,各変数に値が代入されます.



 プログラム例 14.6.1  実行結果
#include <stdio.h>

void main(void){
  int a, b, c;
  FILE *fp; /* ファイルポインターの宣言 */
   
  /* 操作1:既存のファイルを開く*/
  fp = fopen("c:\\data\\abc.txt","r");

    /* 操作2:ファイルからデータを読む */
    fscanf(fp,"%5d,%5d,%5d\n",&a,&b,&c);

    printf("%5d,%5d,%5d\n", a, b, c);

  /* 操作3:ファイルを閉じる */
  fclose(fp);
}
    3,    5,    8



 14.7 既存のファイルにデータを追加する

 こんどは,作成済みのデータファイルにデータを追加する手順を説明します.プログラム例14.5.1に例を示します.
 追加書き込みの場合,ファイルを開くときのモードを"a"(append)とします.
   fp = fopen("c:\\data\\abc.txt","a");
書き込みには,プログラム例4.3.1と同様,fprintf()関数が使えます.
   fprintf(fp,"%5d,%5d,%5d\n",a, b, c);
もちろん,データ書き込み終了後は,ファイルを閉じる手続きが必要なことはいうまでもありません.

このプログラム例の場合も,実行結果にファイルの内容は表示されませんが,「メモ帳」を使ってファイルを読み込みデータが追加されたことを確認してみてください.


注意)ファイルにデータを追加するとき,fopen()のモードを"w"にすると既存のファイルは削除され,同じ名前のファイルが新たに作成されることになります.したがって,既存のファイルに書き込んであったデータは全て消失します.


 プログラム例 14.7.1  実行結果
#include <stdio.h>

void main(void){
  int a, b, c;
  FILE *fp; /* ファイルポインターの宣言 */

  a = 4; b = 7; c = a + b;   
    /* 既存のファイルを開く*/
  fp = fopen("c:\\data\\abc.txt","a");

    printf("%5d,%5d,%5d\n", a, b, c);

    /* 追加データを書き込む */
    fprintf(fp,"%5d,%5d,%5d\n",a, b, c);

  /* ファイルを閉じる */
  fclose(fp);
}
    4,    7,   11



 14.8 fopen()関数の戻り値の使い方
 プログラムからファイルを開くとき,次のような場合,プログラムは実行を停止します.
 1)ファイルへのパス名やファイル名を間違えた.
 2)指定した記憶装置(ドライブ)やメディア(フロッピーディスクなど)が存在しなかった.
 3)指定したフォルダーが存在しなかったり,読み込み時や追加時にあるべきファイルが存在しなかった.

ファイルのオープンに失敗したとき,プログラムを正常に終了させるには,fopen()関数の戻り値を 使います.14.4節で紹介したように,fopen()関数は,ファイルを開くことに失敗したらNULLを返します.
プログラム例を14.8.1に示します.プログラム例では,存在しないファイルを開くように指定しています.
このように,ファイルを開くとき,失敗してもプログラムが異常終了しないよう配慮するのがプログラムを書くときの常識です.

※ if((fp = fopen("c:\\datada\\xxx.txt","w"))==NULL)の表現が理解できないときは,NULLが\0であることを思い出して, 「5.演算子と演算結果」を参考にしてください.(このような表現になれることは,とても大切なことです)


 プログラム例 14.8.1  実行結果
#include <stdio.h>

void main(void){
  int a, b, c;
  FILE *fp;

  if((fp = fopen("c:\\data\\abc.txt","r"))!=NULL){
    fscanf(fp,"%5d,%5d,%5d\n",&a,&b,&c);
    printf("%5d,%5d,%5d\n", a, b, c);
    fclose(fp);
  }
  else{
     printf("指定のファイルが見つかりません\n");
     printf("パスやファイル名をチェック!\n");
  }
}
指定のファイルが見つかりません
パスやファイル名をチェック!





 14.9 fscanf()関数の戻り値の使い方

 ファイル中でのデータの並び方
   -5,   28,   -7
   -4,   19,   -5
   -3,   12,   -3
   -2,    7,   -1
   -1,    4,    1
    0,    3,    3
    1,    4,    5
    2,    7,    7
    ..., ..., ...
    EOF
 通常,ファイル中のデータは,上記のように同一パターンで繰り返し記録されます.また,記録されたデータの 件数も一定していないのが普通です.データの記録件数が一定してなければ,繰り返し文を使ってデータを読むプログラムでは, 読み込みの回数を固定できないことになります.
 fscanf()関数に限らず,ファイルからデータを読み込む(入力)関数には,ファイルの終点を検出する機能が 備わっていて,読み込むべきデータの件数が具体的にわからなくてもファイルの終了点を検出することができます.

 先に,紹介したようにfscanf()関数の場合は,ファイルの終了点を検出すると, 戻り値としてEOFという値を返すように作られています.
プログラム例14.9.1は,fscanf()関数の戻り値をチェックしながら,読み込むべきデータが尽きたとき, 読み込み処理を正常に終了させるくふうをしたものです.
これもファイル処理のプログラム作成するときの必須の知識です.


 プログラム例 14.9.1  実行結果
#include <stdio.h>

void main(void){
  int a, b, c;
  FILE *fp;

  if((fp = fopen("c:\\data\\abc.txt","r"))!=NULL)
  {
    while(fscanf(fp,"%5d,%5d,%5d\n",&a,&b,&c)!=EOF)
    {
      printf("%5d,%5d,%5d\n", a, b, c);
    }
    fclose(fp);
  }
  else{
     printf("指定のファイルが見つかりません\n");
     printf("パスやファイル名をチェック!\n");
  }
}
   -5,   28,   -7
   -4,   19,   -5
   -3,   12,   -3
   -2,    7,   -1
   -1,    4,    1
    0,    3,    3
    1,    4,    5
    2,    7,    7
    3,   12,    9
    4,   19,   11
    5,   28,   13
    6,   39,   15
    7,   52,   17
    8,   67,   19
    9,   84,   21
   10,  103,   23