C言語基礎|ファイルのクローズ

「開いたら、ちゃんと閉じる。これが“安全なファイル処理”の第一歩!」

ノートって、読み書きが終わったら閉じますよね。机の上に開きっぱなしだと邪魔だし、どこまで読んだかも曖昧になりがちです。
C言語のファイルも同じで、使い終わったら**ファイルとストリームの結び付きを切り離して、後片付け(クローズ)**をします。

この「後片付け」を担当するのが fclose 関数です。
クローズするときは、ただ“閉じる”だけじゃなくて、まだファイルに書き込まれていないデータをまとめて書き出す(フラッシュ)など、大事な処理も一緒に行われます。
なので、ファイル処理では「開く」だけでなく「閉じる」までセットで覚えるのがとっても大切です。

クローズすると何が起きるの?

fclose は、ストリームとファイルを安全に切り離すために、いろいろやってくれます。

fclose が行う主なこと(イメージ)

処理何が起きる?なぜ必要?
フラッシュ書き込み待ちのデータをホスト環境へ引き渡す書いたはずの内容がファイルに残らない事故を防ぐ
未読データの破棄読み取り用に溜まっていた未処理データを捨てる中途半端な状態を残さない
結び付きを解除ストリームをファイルから切り離すこれ以上そのストリームで操作しないため
バッファ解放自動確保されたバッファを解放するメモリや資源の無駄を防ぐ

表の説明

  • 「書き込み」はすぐにファイルへ直書きされず、途中で溜められることがあります(バッファリング)。
  • fclose は最後にまとめて書き出すので、閉じ忘れると“保存したつもり”が消えることが起こり得ます。
  • だから「開いたら閉じる」は、習慣として身につけるのが一番強いです。

図でつかむ:ファイルのクローズ

図:fopen で受け取った fp を fclose に渡すだけ

fp = fopen(ファイル名, モード);
      ↓
(読み書き)
      ↓
fclose(fp);

[ストリーム fp] ──X── [ファイル]
   ↑バッファは整理・解放

図の説明

  • fopen が返してくれた FILE*(ここでは fp)が「操作の取っ手」です。
  • クローズするときは、その取っ手をそのまま fclose に渡せばOK。
  • クローズ後は fp が指していたストリームはもう使えません(使うと危険)。

fclose の書式(命令の形式)

書式

項目内容
ヘッダ#include <stdio.h>
形式int fclose(FILE *stream);
引数stream:閉じたいストリーム(FILE*)
返り値成功:0 / エラー:EOF

表の説明

  • fclose は「成功か失敗か」を返してくれるので、必要ならチェックできます。
  • 特に重要なデータを書き込む場面では、fclose の戻り値チェックが安心です。

サンプルプログラム

ファイルを開けたか確認して、開けたら閉じるプログラム例です。

プロジェクト名:chap13-3-1 ソースファイル名:chap13-3-1.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

Windows の Visual Studio が実行環境の場合、以下のパスに「data.txt」がない状態と配置した状態で実行結果を確認します。
C:\Users\joeac\source\repos\chap13-3-1\chap13-3-1

#include <windows.h>
#include <stdio.h>

int main(void)
{
    SetConsoleOutputCP(65001); // 出力をUTF-8に設定
    FILE *fp;

    fp = fopen("data.txt", "r");   /* 読み取りモードでオープン */

    if (fp == NULL) {
        printf("data.txt を開けませんでした。ファイルがあるか確認してください。\n");
        return 0;
    }

    printf("data.txt を開きました。いまからクローズします。\n");

    if (fclose(fp) == 0)
        printf("クローズ完了!後片付けもバッチリです。\n");
    else
        printf("クローズでエラーが起きました。\n");

    return 0;
}

このプログラムのポイント(文章で説明)

  • fopen で data.txt を r(読み取り)で開きます
  • 失敗したら fp は NULL なので、案内を表示して終了します
  • 成功したら「開けたよ」と表示し、すぐ fclose(fp) で閉じます
  • fclose の返り値を見て、クローズ成功かどうかをメッセージで分けています
  • 「開いたら閉じる」の形が一番シンプルに確認できます

失敗時の分岐がなぜ大事?

ファイル処理は「失敗する可能性」が普通にあります。たとえば、

  • ファイルが存在しない
  • 権限がなくて開けない
  • すでに別のプログラムがロックしている(環境による)
  • ディスクやデバイスの問題

だから「fp が NULL だったらどうする?」を最初から書いておくと、プログラムが強くなります。

成功ルートと失敗ルート

fopen 成功 → fp は有効 → 読み書き → fclose
fopen 失敗 → fp は NULL → エラーメッセージ → 終了

説明

  • 成功時だけ fclose を呼べばOKです(NULL を fclose に渡すのは危険なので避けます)。
  • こういう分岐が「安全なファイル処理」の基本形になります。

「開く・閉じる」がセットな理由(バッファの話をやさしく)

ファイルに書く処理は、毎回すぐディスクへ書くとは限りません。
効率のために、いったんメモリ上のバッファに溜めて、まとめて書き出すことがあります。

図:書き込みがバッファに溜まってから保存されるイメージ

fprintf などで出力
   ↓
[バッファに一時保存]  ← ここに残っていることがある
   ↓(fclose でフラッシュ)
[ファイルに反映]

図の説明

  • fclose は「残っている分もちゃんと書いてね」という締めの処理をしてくれます。
  • だから閉じ忘れると、最後の一部がファイルに残らないことがあります。
  • 「処理が終わったら fclose」はデータ保護の意味でも重要です。

演習問題

演習13-1:ファイルの存在確認+クローズ確認

キーボードからファイル名を読み取り、そのファイルが開けるなら
そのファイルは開けました と表示し、必ず fclose で閉じる。
開けないなら そのファイルは開けません と表示するプログラムを作成せよ。

解答例

プロジェクト名:chap13-3-2 ソースファイル名:chap13-3-2.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

Windows の Visual Studio が実行環境の場合、以下のパスにファイルを配置します。
C:\Users\<ユーザー名>\source\repos\chap13-2-2\chap13-2-2

#include <windows.h>
#include <stdio.h>

int main(void)
{
    SetConsoleOutputCP(65001); // 出力をUTF-8に設定
    char name[256];
    FILE *fp;

    printf("確認したいファイル名を入力してください: ");
    if (scanf("%255s", name) != 1) {
        printf("入力を読み取れませんでした。\n");
        return 0;
    }

    fp = fopen(name, "r");
    if (fp == NULL) {
        printf("そのファイルは開けません。\n");
        return 0;
    }

    printf("そのファイルは開けました。\n");

    if (fclose(fp) == 0)
        printf("クローズも成功しました。\n");
    else
        printf("クローズでエラーが起きました。\n");

    return 0;
}

解説

  • scanf でファイル名を受け取り、fopen(name, "r") を試します
  • 成功したら fp は有効なので、fclose(fp) で後片付けします
  • fclose の戻り値で「閉じる処理まで安全に終わったか」を確認できます
  • この形は「存在確認」にもなります(開ける=少なくとも読み取りできる状態)

演習13-2:ファイルを空にしてから「消去しました」と表示

キーボードからファイル名を読み取り、そのファイルを空にする(中身を消去する)プログラムを作成せよ。
成功したら ファイルを空にしました と表示し、失敗したら 失敗しました と表示すること。

ヒント:書き込みモードでオープンするとよい。

解答例

プロジェクト名:chap13-3-3 ソースファイル名:chap13-3-3.c

Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。

Windows の Visual Studio が実行環境の場合、以下のパスにファイルを配置します。
C:\Users\<ユーザー名>\source\repos\chap13-2-3\chap13-2-3

#include <windows.h>
#include <stdio.h>

int main(void)
{
    SetConsoleOutputCP(65001); // 出力をUTF-8に設定
    char name[256];
    FILE *fp;

    printf("空にしたいファイル名を入力してください: ");
    if (scanf("%255s", name) != 1) {
        printf("入力を読み取れませんでした。\n");
        return 0;
    }

    fp = fopen(name, "w");  /* w は長さ0にする(上書き開始) */
    if (fp == NULL) {
        printf("失敗しました。\n");
        return 0;
    }

    if (fclose(fp) == 0)
        printf("ファイルを空にしました。\n");
    else
        printf("クローズでエラーが起きました。\n");

    return 0;
}

解説

  • w で開くと、既存ファイルは内容が消えて0からになります(新規作成にもなります)
  • 開けたらすぐ閉じても、結果として「空ファイル」ができあがります。
  • 重要ファイルに対して実行すると取り返しがつかないので、練習用のファイルで試すのが安全です。