C言語のファイル操作、なんだか難しそうって思っていませんか? プログラムを書いていると、結果を保存したり、設定を読み込んだりしたくなる場面、ありますよね。実は、基本さえ押さえれば意外とできちゃうんです!
この記事では、C言語を使ったファイルの基本的な扱い方、つまりファイルの開け閉めからデータの読み書きまで、初心者の方でもつまずかないように、サンプルコードを交えながら丁寧に解説していきます。
この記事で学べること
- ファイル操作の基本的な考え方
- ファイルを開いたり閉じたりする方法(fopen, fclose)
- ファイルにデータを書き込む方法(fprintf, fputc, fputs)
- ファイルからデータを読み込む方法(fscanf, fgetc, fgets)
- ファイル操作で気をつけるべきポイント
C言語のファイル操作とは?基本を理解しよう
まず、そもそもなんでプログラムでファイル操作が必要なんでしょう? それは、プログラムが動いている間のデータ(変数の中身とか)は、プログラムが終わると消えてしまうからです。
例えば、計算結果やユーザーが入力した情報を、プログラムが終わった後も残しておきたい場合、ファイルに書き込んで保存(データの永続化って言います)する必要が出てきます。
逆に、あらかじめ用意しておいた設定データや大量の情報を、プログラムで読み込んで使いたいときもありますね。
ファイル操作を覚えると、こんなことができるようになります。
- ゲームのセーブデータを作る
- プログラムの設定をファイルから読み込む
- 処理結果をログファイルとして記録する
ファイル操作の中心となるのがファイルポインタです。これは、プログラムが今ファイルのどの部分を読み書きしているかを示す目印のようなもの。このファイルポインタを使って、ファイルを操作していくイメージを持つと分かりやすいかもしれません。
C言語でファイルを開く・閉じる基本操作 (fopen, fclose)
ファイル操作の基本中の基本、それがファイルの「開く(オープン)」と「閉じる(クローズ)」です。
料理で言えば、冷蔵庫のドアを開けて食材を取り出し、使い終わったらドアを閉める、みたいな感じですね。これをやらないと始まらないし、後片付けもできません。
C言語では、主に `fopen()` 関数でファイルを開き、`fclose()` 関数でファイルを閉じます。まずは、この2つの関数の使い方をしっかり覚えましょう。
ファイルを開く関数 fopen() の使い方とモード
ファイルを開くには `fopen()` 関数を使います。この関数は、どのファイルを、どんな目的で開くかを指定して、ファイルポインタを返してくれます。
基本的な書き方はこんな感じです。
FILE *fp; fp = fopen("ファイル名", "オープンモード");
第一引数には開きたいファイルの名前(パス)を文字列で指定します。第二引数のオープンモードは、ファイルを開く目的を示す文字列です。よく使うモードをいくつか紹介しますね。
"r"
: 読み込み用 (ファイルが存在しないとエラー)"w"
: 書き込み用 (ファイルが存在しない場合は新規作成、存在する場合は上書き)"a"
: 追加書き込み用 (ファイルが存在しない場合は新規作成、存在する場合は末尾に追加)"rb"
,"wb"
,"ab"
: それぞれバイナリモードでの読み込み、書き込み、追加書き込み
モードの選択はめちゃくちゃ大事です!間違えると、ファイルが消えちゃったり、思ったように読み書きできなかったりしますからね。
そして、`fopen()` が失敗した場合(ファイルが見つからない、アクセス権がないなど)、NULLという特別な値を返します。なので、ファイルを開いた直後には、必ずファイルポインタがNULLでないかチェックする習慣をつけましょう。これがエラー処理の基本です。
#include <stdio.h> int main(void) { FILE *fp; // ファイルポインタの宣言 // ファイル "test.txt" を書き込みモード("w")で開く fp = fopen("test.txt", "w"); // ファイルオープンが成功したかチェック if (fp == NULL) { printf("ファイルを開けませんでした。\n"); return 1; // エラー終了 } printf("ファイルを開きました。\n"); // ... ここにファイルへの書き込み処理などを書く ... fclose(fp); // ファイルを閉じる printf("ファイルを閉じました。\n"); return 0; }
ファイルを閉じる関数 fclose() の重要性
ファイルを開いたら、使い終わった後に必ず `fclose()` 関数で閉じなければいけません。これは絶対に忘れないでください!
fclose(fp); // fp は fopen で取得したファイルポインタ
なぜ閉じる必要があるのか?理由はいくつかあります。
- 書き込みデータの保証
- 書き込みモードで開いたファイルは、`fclose()` を呼ぶことで初めて、書き込んだ内容が完全にファイルに反映されることが保証されます(バッファのフラッシュ)。途中でプログラムが異常終了したりすると、書き込み内容が失われることがあるんです。
- リソースの解放
- プログラムがファイルを開いている間は、OSのリソース(メモリなど)を使っています。必要なくなったファイルを閉じないと、無駄にリソースを消費し続けてしまいます。同時に開けるファイルの数には上限があるので、開きっぱなしはダメ、絶対。
- 他のプログラムからのアクセス
- ファイルを開きっぱなしにしていると、他のプログラムがそのファイルを使えなくなる場合があります。
`fopen()` と `fclose()` は必ずセットで使う、と覚えておきましょう。開けたら閉める、プログラミングのお作法です。
C言語でのファイル書き込み操作 (fprintf, fputc, fputs)
ファイルを開いたら、いよいよデータの書き込みです。
C言語には、ファイルにデータを書き込むための関数がいくつか用意されています。ここでは代表的な `fprintf()`, `fputc()`, `fputs()` を見ていきましょう。
fprintf() を使った書式指定書き込み
画面に文字を表示する `printf()` 関数はお馴染みですよね。`fprintf()` は、そのファイル版です。`printf()` と同じように、書式指定子(%d や %s など)を使って、変数の中身を整形してファイルに書き込むことができます。
書き方は `printf()` と似ていますが、最初の引数にファイルポインタを指定するのがポイントです。
fprintf(fp, "書式指定文字列", 引数1, 引数2, ...);
例えば、ファイルポインタ `fp` が指すファイルに、整数と文字列を書き込むならこんな感じ。
int score = 100; char name[] = "Taro"; fprintf(fp, "Name: %s, Score: %d\n", name, score);
これで、ファイルには Name: Taro, Score: 100 と書き込まれます。改行したければ `\n` を忘れずに。
fputc(), fputs() を使った文字・文字列書き込み
もっとシンプルに、1文字だけ書き込みたい、または文字列をそのまま書き込みたい、という場合には `fputc()` や `fputs()` が便利です。
fputc()
は、1文字をファイルに書き込みます。
int ch = 'A'; fputc(ch, fp); // ファイルポインタ fp が指すファイルに文字 'A' を書き込む
fputs()
は、文字列をファイルに書き込みます。ただし、文字列の最後にあるはずのヌル文字(\0)は書き込まない点に注意が必要です。
char message[] = "Hello, World!"; fputs(message, fp); // ファイルポインタ fp が指すファイルに "Hello, World!" を書き込む
`fputs()` は自動で改行してくれないので、改行が必要なら自分で `fputc('\n', fp);` や `fputs("\n", fp);` を追加する必要がありますよ。
C言語のファイル書き込みのサンプルプログラム
では、実際にファイルに書き込むプログラムを書いてみましょう。ここでは、`fopen()`, `fprintf()`, `fputs()`, `fputc()`, `fclose()` を使ってみます。
ソースコード: write_sample.c
#include <stdio.h> int main(void) { FILE *fp; char name[] = "Jiro"; int age = 25; // "output.txt" を書き込みモード("w")で開く fp = fopen("output.txt", "w"); if (fp == NULL) { printf("ファイルを開けませんでした。\n"); return 1; } printf("output.txt を書き込み用に開きました。\n"); // fprintf で書き込み fprintf(fp, "--- Profile ---\n"); fprintf(fp, "Name: %s\n", name); fprintf(fp, "Age: %d\n", age); // fputs で書き込み fputs("This is a sample message.\n", fp); // fputc で書き込み fputc('-', fp); fputc('-', fp); fputc('-', fp); fputc('\n', fp); // 改行 printf("ファイルへの書き込みが完了しました。\n"); // ファイルを閉じる fclose(fp); printf("ファイルを閉じました。\n"); return 0; }
コンパイルと実行
gcc write_sample.c -o write_sample ./write_sample
実行結果 (output.txt の中身)
--- Profile --- Name: Jiro Age: 25 This is a sample message. ---
どうでしょう?プログラムを実行すると、同じディレクトリに `output.txt` というファイルが作られ、指定した内容が書き込まれているはずです。簡単ですよね!
C言語でのファイル読み込み操作 (fscanf, fgetc, fgets)
書き込みができたら、次はファイルからデータを読み込む方法です。読み込みにもいくつか関数がありますが、ここでは `fscanf()`, `fgetc()`, `fgets()` を中心に見ていきましょう。
読み込み操作で特に気をつけたいのは、ファイルの終わり(EOF: End Of File)をどうやって知るか、という点です。
C言語のファイル読み込みのサンプルプログラム
読み込みは、書き込みとセットで覚えるのが効率的です。ここでは、先ほど作成した `output.txt` を読み込んで、その内容を画面に表示するプログラムを作ってみましょう。
ファイルの終わりまで1行ずつ読み込むには `fgets()` がよく使われます。`fgets()` は、指定した文字数分、または改行までを読み込む関数で、ファイルの終わりに達すると NULL を返します。
入力ファイル (output.txt)
--- Profile --- Name: Jiro Age: 25 This is a sample message. ---
ソースコード: read_sample.c
#include <stdio.h> #define BUFFER_SIZE 256 // 1行の最大文字数(適宜調整) int main(void) { FILE *fp; char buffer[BUFFER_SIZE]; // 読み込み用バッファ // "output.txt" を読み込みモード("r")で開く fp = fopen("output.txt", "r"); if (fp == NULL) { printf("ファイルを開けませんでした。\n"); return 1; } printf("output.txt を読み込み用に開きました。\n\n"); printf("--- ファイル内容 ---\n"); // ファイルの終わり(EOF)まで1行ずつ読み込んで表示 // fgetsは読み込み成功時にバッファのポインタを、失敗またはEOFでNULLを返す while (fgets(buffer, BUFFER_SIZE, fp) != NULL) { printf("%s", buffer); // bufferには改行も含まれていることが多い } printf("\n--- 読み込み完了 ---\n\n"); // ファイルを閉じる fclose(fp); printf("ファイルを閉じました。\n"); return 0; }
コンパイルと実行
gcc read_sample.c -o read_sample ./read_sample
実行結果 (コンソール表示)
output.txt を読み込み用に開きました。 --- ファイル内容 --- --- Profile --- Name: Jiro Age: 25 This is a sample message. --- --- 読み込み完了 --- ファイルを閉じました。
この例では `fgets()` を使って1行ずつ読み込みました。`fscanf()` は `scanf()` のファイル版で、書式を指定して読み込めますが、スペースや改行の扱いに少しクセがあるので注意が必要です。
`fgetc()` は1文字ずつ読み込む関数です。ファイルの終端(EOF)判定は、これらの関数の戻り値を使って行います。EOFのチェックは読み込みループの必須項目ですよ!
C言語 ファイル操作を行う上での注意点
ファイル操作は便利ですが、いくつか注意しないと予期せぬエラーやデータ消失につながることがあります。ここでは、特に気をつけてほしいポイントをまとめました。
`fopen()` の戻り値チェックは絶対!
ファイルが存在しない、アクセス権がないなどで `fopen()` が失敗するとNULLが返ります。NULLチェックを怠ると、その後のファイル操作でプログラムがクラッシュします。必ずチェックしましょう。`fclose()` を忘れない!
開けたら閉じる! 書き込み内容の保証やリソース解放のために、ファイルの利用が終わったら必ず `fclose()` を呼び出すこと。プログラムの出口が複数ある場合は、どこを通っても閉じるように気をつけてください。適切なオープンモードを選ぶ
読み込みたいのに "w" で開くとファイル内容が消えます。追記したいのに "w" で開いても上書きされます。"r" で存在しないファイルを開こうとするとエラーになります。目的(読み/書き/追記)とファイルの存在有無を考えてモードを選びましょう。ファイルパスの指定
ファイル名だけでなく、必要に応じてディレクトリパスも指定します。実行ファイルからの相対パスか、絶対パスかを意識しましょう。違うディレクトリのファイルを開きたい場合は注意が必要です。テキストモードとバイナリモード
Windows環境などでは、テキストモード("r", "w", "a" など)とバイナリモード("rb", "wb", "ab" など)で改行コードの扱いが変わることがあります。テキストファイル以外(画像など)を扱う場合は、基本的にバイナリモードを使います。バッファオーバーラン対策 (特に `fgets()` )
`fgets()` は読み込む最大サイズを指定できるので安全性が高いですが、指定したバッファサイズよりも長い行が存在する可能性も考慮する必要があります。十分なサイズのバッファを用意しましょう。`fscanf()` などを使う場合も、想定外の入力でバッファあふれが起きないか注意が必要です。EOF(ファイルの終端)判定
ファイルを読み込むループでは、正しくファイルの終端を検出することが必須です。`fgets()`, `fgetc()`, `fscanf()` などの関数の戻り値を使って適切に判定しないと、無限ループになったり、ファイルの途中までしか読めなかったりします。これらの点に気をつけるだけで、ファイル操作はずっと安全で確実になりますよ!
【まとめ】C言語のファイル操作をマスターしてプログラムの幅を広げよう
お疲れ様でした! 今回はC言語のファイル操作の基本について、ファイルの開け閉めから読み書き、そして注意点まで解説してきました。
最初は `fopen()`, `fclose()`, `fprintf()`, `fgets()` あたりの基本的な関数から使い方を覚えて、実際に動かしてみるのが一番です。サンプルコードを参考に、まずは簡単なデータの保存や読み込みに挑戦してみてください。
ファイル操作ができるようになると、作れるプログラムの幅がぐんと広がります。データの永続化、設定ファイルの利用、ログの出力など、より実用的なプログラムが書けるようになるはずです。
もちろん、ファイル操作にはもっと色々な関数やテクニックがありますが、まずは今回紹介した基本をしっかり自分のものにすることがスタートラインです。
恐れずに、どんどんファイル操作を使っていきましょう!
【関連記事】
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。