導入
次に起動したときも同じデータを使いたい、実行結果を他のプログラムに渡したい——そんなときに使うのが「ファイル」への保存です。C言語では fopen でファイルを開き、fclose で閉じることでファイルを操作します。
説明
ファイルを開くには次のように書きます。
FILE *fp = fopen("パス", "モード");
モードには代表的に次の3つがあります。
"r"… 読み込み専用。ファイルが存在しないと失敗する。"w"… 書き込み専用。ファイルが無ければ新規作成、あれば中身を空にしてから書き込む(上書き)。"a"… 追記専用。ファイルの末尾にどんどん追加していく。無ければ新規作成。
fopen の戻り値は FILE 型へのポインタ(FILE *)です。ファイルを開けなかった場合(存在しない・権限がない等)は特別な値 NULL が返ります。開けたかどうかを確かめずに使うと危険なので、必ず if (fp == NULL) { ... } でチェックしてから使う癖をつけましょう。使い終わったファイルは fclose(fp); で必ず閉じます。閉じ忘れると、書き込んだ内容が確定しない場合があります。
flowchart LR w["fopen(path, \"w\")"] --> fp["fputs(...) で書き込む"] --> c1["fclose(fp)"] c1 --> r["fopen(path, \"r\")"] r --> read["fgetc(fp) を繰り返して読む"] --> c2["fclose(fp)"]
次の例では、/home/user/memo.txt というファイルに1行書き込んでから、同じファイルを読み込みモードで開き直し、1文字ずつ fgetc で読み出して表示しています(1文字ずつ読む関数は fgetc。行ごとまとめて読む方法は次のレッスン以降で学びます)。最後に、存在しないファイルを "r" で開こうとして NULL が返る様子も確認します。
#include <stdio.h>
int main(void) {
FILE *fp = fopen("/home/user/memo.txt", "w");
if (fp == NULL) {
printf("書き込み用に開けませんでした\n");
return 1;
}
fputs("Hello, file!\n", fp);
fclose(fp);
printf("書き込み完了\n");
fp = fopen("/home/user/memo.txt", "r");
if (fp == NULL) {
printf("読み込み用に開けませんでした\n");
return 1;
}
printf("読み込み結果: ");
int c;
while ((c = fgetc(fp)) != EOF) {
putchar(c);
}
fclose(fp);
FILE *missing = fopen("/home/user/nothing.txt", "r");
if (missing == NULL) {
printf("存在しないファイルなのでNULLが返りました\n");
} else {
fclose(missing);
}
return 0;
}
"a"(追記)モードは、実行するたびにファイルの末尾へ書き足していきます。
#include <stdio.h>
int main(void) {
FILE *fp = fopen("/home/user/log.txt", "a");
fputs("追記した行\n", fp);
fclose(fp);
printf("追記しました(実行するたびに1行ずつ増えます)\n");
return 0;
}
やってみよう
上のコードを実行して、書き込み・読み込みができていることを確認しましょう。2番目のコードを何度か実行すると、追記されて増えていくことも確かめてみてください。また、fopen のモードを "r" に変えて、まだ存在しないファイル名を指定すると NULL チェックが発動する様子も試してみましょう。
演習
/home/user/greeting.txt に "Konnichiwa!\n" という文字列を書き込んでから、同じファイルを読み込んで表示するプログラムを書いてください。書き込み用に開けなかった場合は「エラー」と表示してください。
ヒント1を見る
FILE *fp = fopen("/home/user/greeting.txt", "w"); で開き、fputs("Konnichiwa!\n", fp); で書き込みます。
ヒント2を見る
書き込んだら fclose で閉じ、もう一度 "r" で開いて fgetc のループ(while ((c = fgetc(fp)) != EOF) putchar(c);)で読み出します。