Linux講座にようこそ。このページは「C言語プログラミング入門 - 第14章.ライブラリ関数 - 入出力ライブラリ」です。

C言語プログラミング入門

14. ライブラリ関数(7/36) - 入出力ライブラリ(6/10)

14.9 ファイルの終端及び、エラーの検出関数

入出力関数の多くはファイルの終端を検出すると、EOF(end of file)やNULLを返しますし、エラーを検出した場合も同じ値を返します。従って、本当にEOFなのかエラーなのか分かりません。そこで、厳密にEOFなのかエラーなのかを調べたいような場合に、ここで紹介する関数を使うとよいでしょう。

14.9.1 feof関数

feof関数はファイルポインタに対応したファイルのEOF(end of file)の状態を調べます。

【表14-1-25】 feof関数
形式#include <stdio.h>
int feof(FILE *fp);
返り値EOFであれば0以外の値を返します。
引数
FILE *fp
EOFかどうかを調べるファイルのファイルポインタを指定します。

14.9.2 ferror関数

ferror関数はファイルポインタに対応したファイルのエラー状態を調べます。

【表14-1-26】 ferror関数
形式#include <stdio.h>
int ferror(FILE *fp);
返り値エラーであれば0以外の値を返します。
引数
FILE *fp
エラーかどうかを調べるファイルのファイルポインタを指定します。

14.9.3 clearerr関数

clearerr関数はファイルポインタに対応したファイルのEOF(end of file)とエラーの状態をクリアします。

【表14-1-27】 clearerr関数
形式#include <stdio.h>
void clearerr(FILE *fp);
返り値ありません。
引数
FILE *fp
クリアするファイルのファイルポインタを指定します。
使用法、
終端まで入力したファイルを、再度入力したいような場合にも使用できます。

14.9.4 例題

前ページの例題と同じく、下記のような番号・体重・身長・血液型のデータが登録されているex14_1_6.datファイルを入力して標準出力に編集出力します。

1,67,188,A
2,98,176.5,O
3,43.2,156.5,AB
4,55.5,167.5,B
5,75.7,166.5,A
  1. #include <stdio.h>
  2.  
  3. int main(void)
  4. {
  5.     FILE        *fp;
  6.     char        in_file[] = "./DATA/ex14_1_6.dat";
  7.     short int   number;            /* 番号  */
  8.     float       weight;            /* 体重  */
  9.     double      height;            /* 身長  */
  10.     char        blood[4];          /* 血液型 */
  11.     int         return_code = 0;
  12.  
  13.     if((fp = fopen(in_file, "r")) != NULL)
  14.     {
  15.         printf("%-4s  %-8s %-8s %s\n", "番号", "体重", "身長", "血液型");
  16.         while(1)
  17.         {
  18.             /*  番号、体重、身長、血液型を入力 */
  19.             fscanf(fp, "%hd,%f,%lf,%s",
  20.                 &number, &weight, &height, blood);
  21.             /* EOFのチェック */
  22.             if(feof(fp) == 0)
  23.             {
  24.                 printf(" %03hd %6.1f %6.1f  %s\n",
  25.                     number, weight, height, blood);
  26.             }
  27.             else
  28.             {
  29.                 break;             /* 入力終了。繰り返しから抜ける */
  30.             }
  31.         }
  32.         fclose(fp);
  33.     }
  34.     else
  35.     {
  36.         printf("%sがオープン出来ませんでした。", in_file);
  37.         return_code = 1;
  38.     }
  39.  
  40.     return return_code;
  41. }
$ ./ex14_1_8.prg
番号  体重   身長   血液型
 001   67.0  188.0  A
 002   98.0  176.5  O
 003   43.2  156.5  AB
 004   55.5  167.5  B
 005   75.7  166.5  A
$
22行目
feof関数でEOFかどうかを調べて、EOFでなかったら入力した値を表示します。
29行目
EOFだったら入力のための繰り返しから抜け出します。

14.10 バイナリファイルの入出力関数

ファイルにはテキストファイルとバイナリファイルがありますが、今まで説明してきた関数はテキストファイルの入出力用でした。ここで説明するfread関数とfwrite関数はテキストファイルも取り扱えますが、主にバイナリファイルを取り扱う時に使用します。

14.10.1 fread関数

fread関数はファイルポインタに対応したファイルからレコード単位に入力します。入力データの変換は行いません。

【表14-1-28】 fread関数
形式#include <stdio.h>
size_t fread(void *buff, size_t rec_size, size_t rec_num, FILE *fp);
返り値入力したレコードの個数を返します。ファイルの終端(EOF)やエラーを検出した場合は引数で指定したレコード数より小さな値(または0)を返します。
引数
void *buff
入力したデータを格納する領域を指定します。
size_t rec_size
レコード長をバイト単位で指定します。
size_t rec_num
入力するレコードの個数を指定します。
FILE *fp
入力するファイルのファイルポインタを指定します。
使用法、
返り値ではEOFかエラーなのかが明確ではありませんので、明確にしたい場合はeof関数やferror関数を使用します。

14.10.2 fwrite関数

fwrite関数はファイルポインタに対応したファイルにレコード単位に出力します。出力データの変換は行いません。

【表14-1-29】 fwrite関数
形式#include <stdio.h>
size_t fwrite(const void *buff, size_t rec_size, size_t rec_num, FILE *fp);
返り値出力したレコードの個数を返します。エラーを検出した場合は引数で指定したレコード数より小さな値(または0)を返します。
引数
void *buff
出力するデータを格納してある領域を指定します。
size_t rec_size
レコード長をバイト単位で指定します。
size_t rec_num
出力するレコードの個数を指定します。
FILE *fp
出力するファイルのファイルポインタを指定します。
使用法、
返り値ではエラーが明確ではありませんので、明確にしたい場合はferror関数を使用します。

14.10.3 例題

下記のような番号・体重・身長・血液型のデータが登録されているex14_1_6.datファイルを入力して、バイナリのままex14_1_9_out.datファイルに出力します。

1,67,188,A
2,98,176.5,O
3,43.2,156.5,AB
4,55.5,167.5,B
5,75.7,166.5,A
  1. #include <stdio.h>
  2.  
  3. /* 個人情報構造体 */
  4. struct person_info {
  5.     int     number;          /* 番号 */
  6.     double  weight;          /* 体重 */
  7.     double  height;          /* 身長 */
  8.     char    blood[4];        /* 血液型 */
  9. };
  10.  
  11. int main(void)
  12. {
  13.     FILE                *fp_in;
  14.     char                in_file[] = "./DATA/ex14_1_6.dat";
  15.     FILE                *fp_out;
  16.     char                out_file[] = "./DATA/ex14_1_9_out.dat";
  17.     struct person_info  person;
  18.     int                 return_code = 0;
  19.  
  20.     if((fp_in = fopen(in_file, "r")) != NULL)
  21.     {
  22.         if((fp_out = fopen(out_file, "w")) != NULL)
  23.         {
  24.             /* 番号、体重、身長、血液型を入力 */
  25.             while(fscanf(fp_in, "%d,%lf,%lf,%s*",
  26.                     &person.number, &person.weight, &person.height, person.blood) != EOF)
  27.             {
  28.                 /* personの内容を出力 */
  29.                 fwrite(&person, sizeof(person), 1, fp_out);
  30.             }
  31.             fclose(fp_out);
  32.         }
  33.         else
  34.         {
  35.             printf("%sがオープン出来ませんでした。", out_file);
  36.             return_code = 1;
  37.         }
  38.         fclose(fp_in);
  39.     }
  40.     else
  41.     {
  42.         printf("%sがオープン出来ませんでした。", in_file);
  43.         return_code = 1;
  44.     }
  45.  
  46.     return return_code;
  47. }
$ ./ex14_1_9.prg
$
$ od -x -A x -w24 ./DATA/ex14_1_9_out.dat ← odコマンドで、ファイルの内容を十六進数で表示します。
000000 0001 0000 0000 0000 c000 4050 0000 0000 8000 4067 0041 0000
000018 0002 0000 0000 0000 8000 4058 0000 0000 1000 4066 004f 0000
000030 0003 0000 999a 9999 9999 4045 0000 0000 9000 4063 4241 0000
000048 0004 0000 0000 0000 c000 404b 0000 0000 f000 4064 0042 0000
000060 0005 0000 cccd cccc eccc 4052 0000 0000 d000 4064 0041 0000
000078
29行目
person構造体変数の内容を、そのまま(編集しないで)fwrite関数で出力します。第2引数のsizeof(person)はsizeof演算子でperson構造体データの長さを求めています。(sizeof(person_info)でも同じです)