ファイルの仕組み
標準ライブラリ関数を使うと、画面やキーボードへの入出力をすることができました。さらにデータを長く保存したり、大量に読み込んだりするには、ファイルを使ってデータを管理することは欠かせません。
C言語では、ファイルを使ってデータを読み書きするコードも、これまでの入出力のコードとほとんど同じような方式で作成できるようになっています。ファイルへの書き込みは「出力」、ファイルからの読み込みは「入力」の作業に当たります。この節では、ファイルによる入出力操作の基本を学んでいきましょう。
まず、ファイルを扱う場合の基本手順を覚えてください。コード上でファイルの処理を行うには、次のような順序で操作を行います。
ファイルをオープンする
↓
ファイルを読み書きする
↓
ファイルをクローズする
ファイルの「オープン」や「クローズ」とは、操作を始める前に入出力に使われるストリームの概念と実際のファイルを結びつけ、操作」が終わった後に、切り離す処理のことをいいます。ファイルを使う際には、最初にオープン、最後にクローズの作業が必要となります。
では、この手順にしたがって、ファイルを扱うコードを作成してみることにしましょう。なお、ファイルを扱うプログラムの実行方法は、本書冒頭viiiページも参考にしてください。
int sample8()
{
FILE* fp;
fp = fopen("test1.txt","w"); // ファイルをオープンする
if (fp == NULL)
{
//オープンできないときのエラー処理
printf("ファイルをオープンできませんでした。\n");
return 1;
}
else
{
printf("ファイルをオープンしました。\n");
}
fclose(fp); //ファイルをクローズする
printf("ファイルをクローズしました。\n");
return 0;
}
出力結果:
ファイルをオープンしました。
ファイルをクローズしました。
このコードを実行すると、画面に上のような出力がされ、test1.txtという空のファイルが作業中のフォルダ内に作成されます。
このコードでは、ファイルのオープンとクローズだけを行っています。ファイルのオープンは、fopen()関数を使って行います。この関数には、
■ファイル名
■オープンモード
という2つの引数を渡します。ここでは”w”と言うオープンモードを指定しました。すると、ファイルがオープンされ、ファイルをさし示すポインター(FILE *型)が返されます。これをファイルポインタまたはストリームポインタと呼びます。
FILE* fp; //ファイルポインタ
fp = fopen("test1.txt","w"); // ファイルをオープンする。オープンモードを指定する。
なお、なんらかの理由でファイルのオープンができずにエラーとなった場合は、fopen()関数から「NULL」というマクロで定義されたポインタが返されることになっています。
そこで、エラーがおこってファイルポインタがNULLとなった場合には、「オープンできない」というメッセージ出力してプログラムを終了する処理を記述しておきました。
if (fp == NULL)
{
//オープンできないときのエラー処理
printf("ファイルをオープンできませんでした。\n");
return 1;
}
さらに、このコードの最後では、ファイルをクローズする処理を行うfclose()関数を呼び出して、ファイルを閉じます。この操作をしないと、ファイルに問題が起こる場合がありますので、忘れずに行うようにしてください。
fclose(fp); //ファイルをクローズする
ファイルオープンとクローズの構文は次のようになっています。
構文
fopen()関数、fclose()関数
FILE *ファイルポインタ = fopen(“ファイル名”, オープンモード);
fclose(ファイルポインタ);
なお、オープンする際に、fopen()関数に指定できるオープンモードは、次のような種類があります。これからいくつ使っていくことになりますので、表にまとめておきましょう。
オープンモード | 意味 |
---|---|
“w” | 書き込み用にテキストファイルをオープンする |
“r” | 読み込み用にテキストファイルをオープンする |
“a” | 追記用にテキストファイルをオープンする |
“w+” | 更新用にテキストファイルをオープンする(新規作成) |
“r+” | 更新用にテキストファイルをオープンする(ファイルを開く) |
“a+” | 更新のため、追記用にテキストファイルをオープンする |
“wb” | 書き込み用にバイナリファイルをオープンする |
“rb” | 読み込み用にバイナリファイルをオープンする |
“ab” | 追記用にバイナリファイルをオープンする |
重要
ファイルをオープンするには、fopen()関数を使う。
ファイルをクローズするには、fclose()関数を使う。
ファイルに1行を出力する
ファイルをオープンしてクローズする基本のプログラムを実行できたでしょうか?上のコードでは、作成されたファイルは空のままです。そこで処理を追加して、実際にデータをファイルに書き込んでみることにしましょう。
#include <stdio.h>
int sample9()
{
FILE* fp;
fp = fopen("test1.txt", "w"); // ファイルをオープンする
if (fp == NULL)
{
//オープンできないときのエラー処理
printf("ファイルをオープンできませんでした。\n");
return 1;
}
else
{
printf("ファイルをオープンしました。\n");
}
fputs("Hello!\n",fp); //ファイルに出力する
fputs("Goodbye!\n", fp); //ファイルに出力する
printf("ファイルに書き込みました。\n");
fclose(fp); //ファイルをクローズする
printf("ファイルをクローズしました。\n");
return 0;
}
出力結果:
ファイルをオープンしました。
ファイルに書き込みました。
ファイルをクローズしました。
text1.txt
Hello!
Goodbye!
このコードでは、ファイルをオープンしたあとに、ファイルにデータを書き込む処理を追加しています。ファイルに1行ずつ出力するには、fputs()関数などを使います。
この関数は、指定したファイルポインタがさすファイルに、文字列を1行書き出す処理を行います。ただし、この関数を使うと、自動的に、改行されませんので、改行を行う場合は、\nをつける必要があります。test1.txtを開くと、2つの文字列が書き出されているのがわかるでしょうか?
重要
テキストファイルに1行書き込むには、fputs()関数などを使う。
ファイルに書式つきで出力する
では今度は、もう少し扱うデータを増やしてみましょう。キーボードから入力して学生のテストの点数をファイルに書き込んでみることにします。このとき、さきほどのfputs()関数のようにそのまま書き出すのではなく、出力幅を指定してファイルにデータを書き込むことにしましょう。
#include <stdio.h>
#define NUM 5
int sample10()
{
FILE* fp;
int test[NUM];
int i, j;
fp = fopen("test2.txt", "w"); // ファイルをオープンする
if (fp == NULL)
{
//オープンできないときのエラー処理
printf("ファイルをオープンできませんでした。\n");
return 1;
}
else
{
printf("ファイルをオープンしました。\n");
}
printf("%d人の点数を入力してください。\n", NUM);
for (i=0; i<NUM; i++)
{
scanf("%d",&test[i]);
}
for (j=0; j<NUM; j++)
{
fprintf(fp, "No.%-5d%d\n", j + 1, test[j]);
}
printf("ファイルに書き込みました。\n");
fclose(fp); //ファイルをクローズする
printf("ファイルをクローズしました。\n");
return 0;
}
実行結果:
ファイルをオープンしました。
5人の点数を入力してください。
80
60
22
55
30
ファイルに書き込みました。
ファイルをクローズしました。
test2.txt
No.1 80
No.2 60
No.3 22
No.4 55
No.5 30
今度はファイルに出力する際に、fputs()関数ではなく、fprintf()関数という関数を使っています。この関数はprintf()関数と似たもので、ファイルに結びつけられているストリームに対して、書式つきの出力ができるようになっています。この関数では12.1節のprintf()関数と同じ変換仕様を使って書式の設定ができます。
ここでは、出力する際に、出力する幅の指定をしました。この章の最初で学んだ、画面へ出力幅を指定する場合とほとんど同じです。コードを実行すると、上記のようにtest2.txtというファイルが作成され、テストの成績が一定の出力幅で書き込まれます。
重要
テキストファイルに書式つきで書き込むには、fprintf()関数などを使う。
ファイルから1行入力する
では今度は、データを読み込むコードを記述してみましょう。ここでは、さきほど文字列を2行分書き込んだ、test1.txtを利用してます。このファイルの内容を画面に出力してみることにしましょう。
#define NUM 20
int sample11()
{
FILE* fp;
char str1[NUM];
char str2[NUM];
fp = fopen("test1.txt", "r"); // 読み込みモードでオープンする
if (fp == NULL)
{
//オープンできないときのエラー処理
printf("ファイルをオープンできませんでした。\n");
return 1;
}
else
{
printf("ファイルをオープンしました。\n");
}
fgets(str1, NUM - 1, fp); //指定したファイルから最大NUM-1個の文字をstr1に格納して文字列とします
fgets(str2, NUM - 1, fp);
printf("ファイルに書き込まれいる文字列は\n");
printf("%s", str1);
printf("%s", str2);
printf("\n");
fclose(fp); //ファイルをクローズする
printf("ファイルをクローズしました。\n");
return 0;
}
実行結果:
ファイルをオープンしました。
ファイルに書き込まれいる文字列は
hello!
Goodbye!
ファイルをクローズしました。
このコードでは、ファイルに書き込まれている2つの文字列を読み込んで、それを画面に出力しています。読み込みを行う場合には、オープンモールとして読み込み用の”r”を指定します。オープンしたファイルからデータを読み込むには、fgets()関数などを使うことができます。この関数は先ほど書き込みを行った、fputs()関数と逆の処理を行います。この時間数は改行までの1行を読み取って、改行文字ごと格納します。
重要
テキストファイルから1行読み込むには、fgets()関数などを使う。
大量のデータを入力する
ファイルを扱うプログラムは大変便利です。例えば、第7章のテストの成績を処理するコードでは、キーボードから何人もの学生の点数を1人ずつ入力しました。しかし、テストのデータをあらかじめファイルとして用意しておけば、大量のデータを読み込んで、柔軟なコードを記述することができるようになります。
では、試してみましょう。まず、次のようなファイルをテキストエディタで作成してみてください。
test3.txtの下記のデータを用意しておきます。
80
68
22
33
56
78
33
56
これは8人の学生のテストの点数を表すデータです。このたくさんのデータを読み込んで、成績処理を行うコードを記述してみましょう。
#include <stdio.h>
#define NUM 8
int sample12()
{
FILE* fp;
int test[NUM];
int max, min;
int i, j;
fp = fopen("test3.txt", "r"); // ファイルをオープンする
if (fp == NULL)
{
//オープンできないときのエラー処理
printf("ファイルをオープンできませんでした。\n");
return 1;
}
else
{
printf("ファイルをオープンしました。\n");
}
for (i = 0; i < NUM; i++)
{
fscanf(fp, "%d", &test[i]);
}
max = test[0];
min = test[0];
for (j = 0; j < NUM; j++)
{
if (max < test[j])
{
max = test[j];
}
if (min > test[j])
{
min = test[j];
}
printf("No.%-5d%d\n", j+1, test[j]);
}
printf("最高点は%dです。\n", max); //最高点を求めます
printf("最低点は%dです。\n", min); //最低点を求めます
fclose(fp); //ファイルをクローズする
printf("ファイルをクローズしました。\n");
return 0;
}
実行結果:
ファイルをオープンしました。
No.1 80
No.2 68
No.3 22
No.4 33
No.5 56
No.6 78
No.7 33
No.8 56
最高点は80です。
最低点は22です。
ファイルをクローズしました。
このコードでは、あらかじめ保存しておいたファイルからデータを読み込み、最高点と最低点を出力する成績管理を行っています。なお、データの読み込みには、scanf()関数に似たfscanf()関数を使いました。
ここでは8人のデータを用意してますが、このようにファイルを使えば、多くのデータを大量に入力することができるので、様々なデータを扱うプログラムを作成することができるようになります。
重要
テキストファイルから書式つきで読み込むには、fscanf()関数を使う。
コメント