プログラムが終了してもデータを保存しておきたい、設定ファイルを読み込みたい、実行結果をログとして残したい──。こうした要望を叶えるのがファイル入出力の機能です。C言語には、テキストファイルを扱うための基本的で強力な関数が多数用意されています。
この記事では、C言語におけるテキストファイルの読み書きの基本となる**fopen
**, **fclose
**から、1文字ずつ、そして1行ずつファイルを操作する関数までを、分かりやすく解説します。
ファイル操作の第一歩:fopen
と fclose
ファイル操作を行うには、まず目的のファイルを「開く」必要があります。そして、作業が終わったら必ず「閉じる」のが作法です。
FILE *fopen(const char *filename, const char *mode);
- ファイルを指定したモードで開き、ファイルを操作するためのファイルポインタ (
FILE *
) を返します。 - 失敗した場合は
NULL
を返します。fopen
の後のNULLチェックは必須です。
- ファイルを指定したモードで開き、ファイルを操作するためのファイルポインタ (
int fclose(FILE *fp);
- 開いたファイルを閉じます。これにより、書き込んだ内容がディスクに保存され、OSのリソースが解放されます。
主なファイルオープンモード
モード | 説明 | ファイルが存在しない場合 | ファイルが存在する場合 |
"r" | 読み込み専用 (Read) | エラーになる | 先頭から読み込む |
"w" | 書き込み専用 (Write) | 新規作成する | 内容が上書き消去される |
"a" | 追記専用 (Append) | 新規作成する | 末尾に追記する |
1文字単位の入出力:fgetc
と fputc
ファイルを1文字ずつ、きめ細かく読み書きしたい場合に使うのが fgetc
と fputc
です。
int fgetc(FILE *fp);
: ファイルから1文字読み込み、その文字コードを返します。ファイルの終端に達した場合やエラー時にはEOF
という特別な値を返します。int fputc(int character, FILE *fp);
: ファイルに1文字書き込みます。
実践例:ファイルのコピープログラム(1文字ずつ)
source.txt
の内容を destination.txt
に1文字ずつコピーするプログラムです。
#include <stdio.h>
int main(void) {
FILE *source_fp, *dest_fp;
int ch; // fgetcの戻り値がEOF(-1)の可能性があるため、int型で受け取る
// 読み込みファイルを開く
if ((source_fp = fopen("source.txt", "r")) == NULL) {
printf("読み込みファイルのオープンに失敗しました。\n");
return 1;
}
// 書き出しファイルを開く
if ((dest_fp = fopen("destination.txt", "w")) == NULL) {
printf("書き出しファイルのオープンに失敗しました。\n");
fclose(source_fp); // 開いたファイルを閉じる
return 1;
}
// 1文字読み込み、EOFでなければ、その文字を書き出すループ
while ((ch = fgetc(source_fp)) != EOF) {
fputc(ch, dest_fp);
}
printf("ファイルのコピーが完了しました。\n");
// ファイルを閉じる
fclose(dest_fp);
fclose(source_fp);
return 0;
}
1行単位の入出力:fgets
と fputs
ログファイルのように、改行で区切られたテキストを効率的に扱いたい場合は fgets
と fputs
を使います。
char *fgets(char *str, int n, FILE *fp);
: ファイルから最大n-1
文字、または改行までを1行として読み込み、文字列str
に格納します。読み込みに成功すればstr
を、ファイルの終端やエラー時にはNULL
を返します。int fputs(const char *str, FILE *fp);
: ファイルに文字列str
を書き込みます。fgets
と違い、自動で改行は追加されません。
実践例:ファイルのコピープログラム(1行ずつ)
1文字ずつのコピーよりも効率的な方法です。
#include <stdio.h>
#define LINE_BUFFER_SIZE 256
int main(void) {
FILE *source_fp, *dest_fp;
char line_buffer[LINE_BUFFER_SIZE];
if ((source_fp = fopen("source.txt", "r")) == NULL) {
printf("読み込みファイルのオープンに失敗しました。\n");
return 1;
}
if ((dest_fp = fopen("destination.txt", "w")) == NULL) {
printf("書き出しファイルのオープンに失敗しました。\n");
fclose(source_fp);
return 1;
}
// 1行読み込み、NULLでなければ、その行を書き出すループ
while (fgets(line_buffer, LINE_BUFFER_SIZE, source_fp) != NULL) {
fputs(line_buffer, dest_fp);
}
printf("ファイルのコピーが完了しました。\n");
fclose(dest_fp);
fclose(source_fp);
return 0;
}
おまけ:書式付き入出力 fprintf
と fscanf
printf
やscanf
と同じように、書式を指定してファイルに書き込んだり、読み込んだりすることもできます。CSVファイルのような、構造化されたテキストデータを扱う際に非常に便利です。
int fprintf(FILE *fp, const char *format, ...);
:printf
のファイル版。int fscanf(FILE *fp, const char *format, ...);
:scanf
のファイル版。
実践例:スコアデータをファイルに記録・読み込み
#include <stdio.h>
int main(void) {
FILE *fp;
char name[50];
int score;
// --- 書き込み ---
if ((fp = fopen("scores.txt", "w")) == NULL) { return 1; }
fprintf(fp, "Player1 1500\n");
fprintf(fp, "Player2 2300\n");
fclose(fp);
printf("スコアを scores.txt に書き込みました。\n\n");
// --- 読み込み ---
if ((fp = fopen("scores.txt", "r")) == NULL) { return 1; }
printf("スコアを読み込みます:\n");
// ファイルの終わりまで書式付きで読み込む
while (fscanf(fp, "%s %d", name, &score) != EOF) {
printf("名前: %s, スコア: %d\n", name, score);
}
fclose(fp);
return 0;
}
実行結果:
スコアを scores.txt に書き込みました。
スコアを読み込みます:
名前: Player1, スコア: 1500
名前: Player2, スコア: 2300
まとめ
C言語のテキストファイル操作は、プログラムの可能性を大きく広げます。
関数ペア | 単位 | 用途 |
fgetc / fputc | 1文字 | 最も基本的。文字単位での細かな処理に。 |
fgets / fputs | 1行(文字列) | 効率的。ログファイルや設定ファイルの扱いに最適。 |
fscanf / fprintf | 書式付き | CSVのような構造化データを扱う場合に強力。 |
Google スプレッドシートにエクスポート
どの方法を使うにせよ、①fopen
で開き、②処理を行い、③fclose
で閉じるという流れは同じです。この基本をマスターして、データの永続化に挑戦してみましょう!