C++におけるfclose関数を完全ガイド!初心者でもプロも納得の5つのサンプルコード

C++のfclose関数を解説する画像C++
この記事は約16分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

C++でファイル操作を行う際に欠かせないfclose関数について、その使い方から応用例までを詳しく解説します。

この記事を通じて、プログラミング初心者から中級者までがfclose関数の基本的な理解を深めることができます。

fclose関数は、オープンされたファイルポインタを閉じるために使用され、リソースの適切な管理に不可欠です。

この関数の使い方をマスターすることで、ファイル操作に関連する多くのプログラミングエラーを防ぐことができます。

○fclose関数の基本

fclose関数は、標準入出力ライブラリの一部として提供され、ファイルを操作する際に非常に重要な役割を果たします。

具体的には、fopenやfread、fwriteといった関数で開かれたファイルポインタを閉じることに使用されます。

ファイルポインタが指すファイルを正しく閉じることで、オープンされたファイルに対する操作を終了し、システムリソースの解放を促進します。

正しくファイルを閉じない場合、データの損失やメモリリークなどの問題が発生する可能性があります。

□fclose関数とは

fclose関数のプロトタイプは標準ライブラリにおいて下記のように定義されています。

#include <stdio.h>

int fclose(FILE *stream);

この関数は、成功すると0を返し、エラーが発生した場合にはEOF(通常は-1)を返します。

関数の引数には、fclose関数で閉じるべきファイルポインタを指定します。

このファイルポインタは、通常fopen関数によって返される値です。

ファイルを閉じる際には、これまでのファイル操作がすべて正しく行われているかを確認し、エラーがないことを保証するためにエラーチェックも重要になります。

□fclose関数の使い方

ファイルを開き、データの読み書きを行った後、fclose関数を呼び出してファイルポインタを閉じる基本的な流れは下記のようになります。

この例では、テキストファイルを開いて内容を読み込み、その後ファイルを閉じています。

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "r");
    if (file == NULL) {
        printf("ファイルを開けませんでした。\n");
        return 1;
    }

    char buffer[100];
    while (fgets(buffer, 100, file) != NULL) {
        printf("%s", buffer);
    }

    if (fclose(file) == EOF) {
        printf("ファイルを閉じる際にエラーが発生しました。\n");
        return 1;
    }

    return 0;
}

このコードは、ファイルを開いて内容を読み取り、終了時にはfclose関数を使用してファイルを閉じています。fclose関数を呼び出す際には、エラーが発生しないかどうかを確認し、問題があれば適切なエラーメッセージを表示しています。

このような基本的なファイル操作を理解することは、C++プログラミングの基礎を固める上で非常に重要です。

●fclose関数の使い方

fclose関数を適切に使うことで、プログラムの信頼性が向上し、ファイルリソースの無駄遣いを防ぐことができます。

ここでは、具体的な使い方として、ファイルを開いてから閉じるまでの一連の流れについて説明します。

まず、ファイルを開くためにfopen関数を使用し、その後でデータの読み書きを行います。

最終的にfcloseを呼び出してファイルを閉じることで、開かれたファイルとの連携を正しく終了させます。

この際、fcloseが返す値をチェックすることで、ファイルが正常に閉じられたかどうかを確認することが重要です。

○サンプルコード1:ファイルを開いて正しく閉じる

基本形例として、テキストファイルを開き、その内容を表示した後にファイルを閉じるプログラムを見てみましょう。

下記のコードは、fopenでファイルを開き、fgetsを使用してテキストを読み込み、画面に表示します。

最後にfcloseでファイルを閉じています。

#include <stdio.h>

int main() {
    FILE *fp = fopen("sample.txt", "r");
    if (fp == NULL) {
        printf("ファイルオープンに失敗しました。\n");
        return -1;
    }

    char line[1024];
    while (fgets(line, sizeof(line), fp) != NULL) {
        printf("%s", line);
    }

    if (fclose(fp) != 0) {
        printf("ファイルクローズに失敗しました。\n");
        return -1;
    }

    return 0;
}

このプログラムでは、ファイルを安全に開閉する方法を表しています。

特にfcloseが0以外を返した場合には、エラーメッセージを出力しています。

○サンプルコード2:ファイル操作後のエラーチェック

ファイル操作を行った後、ファイルを閉じる前にエラーチェックを行うことは非常に重要です。

下記のサンプルでは、書き込み操作を行った後にfclose関数を呼び出す前にferror関数を使ってエラーの有無を確認しています。

#include <stdio.h>

int main() {
    FILE *fp = fopen("sample.txt", "w");
    if (fp == NULL) {
        printf("ファイルオープンに失敗しました。\n");
        return -1;
    }

    fputs("Hello, world!\n", fp);

    if (ferror(fp)) {
        printf("ファイル書き込み中にエラーが発生しました。\n");
        fclose(fp); // エラーがあってもファイルを閉じる
        return -1;
    }

    fclose(fp);
    return 0;
}

このコードでは、fputsでファイルに書き込みを行った後、ferrorでエラーがあったかどうかをチェックしています。

エラーが発見された場合には、エラーメッセージを出力し、fcloseを呼び出してリソースを解放しています。

○サンプルコード3:複数のファイルを扱う場合の注意点

複数のファイルを同時に扱う場合、それぞれのファイルを適切に管理することが必要です。

下記のサンプルでは、複数のファイルを開き、それぞれのファイルに対して操作を行った後、正しく閉じる方法を表しています。

#include <stdio.h>

int main() {
    FILE *fp1 = fopen("file1.txt", "r");
    FILE *fp2 = fopen("file2.txt", "w");

    if (fp1 == NULL || fp2 == NULL) {
        printf("ファイルのオープンに失敗しました。\n");
        if (fp1 != NULL) fclose(fp1);
        if (fp2 != NULL) fclose(fp2);
        return -1;
    }

    char line[1024];
    while (fgets(line, sizeof(line), fp1) != NULL) {
        fputs(line, fp2);
    }

    fclose(fp1);
    fclose(fp2);
    return 0;
}

このプログラムでは、一つのファイルから読み取った内容を別のファイルに書き込む処理を行っています。

このように、複数のファイルを操作する場合には、それぞれのファイルを個別に閉じることが重要です。

ファイル操作が終了した後、各ファイルをfcloseで閉じることで、リソースのリークを防ぎます。

●よくあるエラーと対処法

C++でのファイル操作中に遭遇するエラーは多岐にわたりますが、特にfclose関数を使用する際には注意が必要です。

エラーの原因を正確に理解し、適切な対処法を学ぶことで、より堅牢なプログラムを作成できるようになります。

○エラー事例1:ファイルが開けない

プログラムがファイルを開けない場合、最も一般的な原因はファイルパスの誤りや、ファイルアクセス権限の問題です。

この問題に対処するためには、ファイルパスが正しいことを確認し、ファイルが存在しアクセス可能であることを保証する必要があります。

エラー処理を適切に行うことで、プログラムの耐障害性を高めることができます。

#include <stdio.h>

int main() {
    FILE *file = fopen("path/to/your/file.txt", "r");
    if (file == NULL) {
        perror("ファイルを開けませんでした");
        return 1;
    }
    // ファイル操作
    fclose(file);
}

このコードでは、fopenがNULLを返した場合にエラーメッセージを出力しています。

perror関数を使用すると、エラーの原因を明確に説明するシステムメッセージが得られます。

○エラー事例2:不完全なファイルクローズ

ファイルが正しく閉じられない場合、データの損失やファイル破損の原因となることがあります。

この問題は、プログラムがクラッシュしたりシステムが予期せず終了したりすると発生しやすくなります。

正常にファイルを閉じるためには、fclose関数を呼び出す前にファイル操作が完了していることを確認し、エラー処理を行うことが重要です。

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        perror("ファイルを開けませんでした");
        return 1;
    }

    fputs("Hello, World!", file);
    // fflush関数を使用して出力バッファをフラッシュする
    fflush(file);

    if (fclose(file) == EOF) {
        perror("ファイルを閉じる際にエラーが発生しました");
        return 1;
    }
}

この例では、fflushを使用してファイルバッファを明示的にフラッシュしています。

これにより、fclose時に未書き込みのデータが失われることがないようにしています。

○エラー事例3:メモリリークの問題

ファイル操作中にメモリリークが発生するのは、開いたファイルポインタが適切に閉じられない場合です。

プログラム内でfopenを使用してファイルを開いた後、どんな状況でも確実にfcloseを呼び出すことが重要です。

特に例外やエラーが発生した際のクリーンアップ処理を忘れないようにしましょう。

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "r");
    if (file == NULL) {
        perror("ファイルを開けませんでした");
        return 1;
    }

    // ファイル操作
    if (fclose(file) != 0) {
        perror("ファイルを閉じる際にエラーが発生しました");
        return 1;
    }
}

このコードは、ファイル操作後にfcloseを呼び出し、その結果をチェックしています。

これにより、ファイルが正常に閉じられたかを確認し、リソースの解放漏れを防ぐことができます。

●fclose関数の応用例

fclose関数は、単なるファイルクローズを超え、多様な応用シナリオで重要な役割を果たします。

効率的なリソース管理からセキュリティ向上まで、fcloseは多くのプログラミングパターンで中心的な機能を担います。

○サンプルコード4:fcloseを使ったログファイルの管理

ログファイルはアプリケーションの動作を記録し、問題解析に不可欠です。

ここでは、アプリケーションによって生成されたログ情報を安全に書き込み、適切にファイルを閉じる方法を紹介します。

#include <stdio.h>

int main() {
    FILE *logFile = fopen("applog.txt", "a");  // ログファイルを追記モードで開く
    if (logFile == NULL) {
        perror("ログファイルを開けませんでした");
        return -1;
    }

    // ログメッセージをファイルに書き込む
    fprintf(logFile, "アプリケーションが起動しました。\n");

    // ファイルを閉じる
    if (fclose(logFile) != 0) {
        perror("ログファイルを閉じる際にエラーが発生しました");
        return -1;
    }

    return 0;
}

このコードでは、ログファイルを開いてメッセージを追加し、その後でファイルを閉じています。

これにより、データが正確にファイルに書き込まれ、プログラム終了時にリソースが適切に解放されることが保証されます。

○サンプルコード5:動的に生成したファイルの適切なクローズ

アプリケーションが実行中にファイルを動的に生成し、それを使用後に適切に管理することは、リソース漏洩を避けるために重要です。

下記の例では、一時ファイルを作成し、使用後にそれを閉じる過程を表しています。

#include <stdio.h>
#include <stdlib.h>

int main() {
    char tempFilename[] = "tempfileXXXXXX";
    int fd = mkstemp(tempFilename);  // 一時ファイルを作成し、ファイルディスクリプタを返す
    if (fd == -1) {
        perror("一時ファイルの作成に失敗しました");
        return -1;
    }

    FILE *tempFile = fdopen(fd, "w+");  // ファイルディスクリプタからFILEオブジェクトを生成
    if (tempFile == NULL) {
        perror("ファイルオープンに失敗しました");
        close(fd);
        unlink(tempFilename);  // 失敗した場合、一時ファイルを削除
        return -1;
    }

    // データをファイルに書き込む
    fprintf(tempFile, "これは一時ファイルのテストです。\n");

    // ファイルを閉じる
    if (fclose(tempFile) != 0) {
        perror("一時ファイルを閉じる際にエラーが発生しました");
        unlink(tempFilename);  // ファイルクローズに失敗した場合、一時ファイルを削除
        return -1;
    }

    unlink(tempFilename);  // 使用後、一時ファイルを削除
    return 0;
}

このコードでは、mkstemp関数を使用して安全に一時ファイルを生成し、fcloseでファイルを閉じた後にファイルを削除しています。

これにより、不要になった一時ファイルがシステムに残ることなく、リソースの適切な管理が行われます。

●エンジニアなら知っておくべき豆知識

プログラミングでは、小さな知識が大きな違いを生むことがあります。

特にファイル操作やメモリ管理に関する深い理解は、エラーの予防と効率的なコードの実装に直結します。

ここでは、fclose関数を取り巻く重要な豆知識をいくつか紹介します。

○豆知識1:ファイル操作のベストプラクティス

ファイル操作を行う際には、いくつかのベストプラクティスを守ることが推奨されます。

例えば、ファイルを開く際には常にエラーチェックを行い、ファイルが正しく開かれたことを確認するべきです。

また、ファイル操作後は速やかにfclose関数を呼び出し、開いたファイルポインタを閉じることが重要です。

これにより、リソースリークを防ぎ、システムの安定性を保つことができます。

例えば、下記のようなコードが考えられます。

#include <stdio.h>

void processFile(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        perror("ファイルを開けませんでした");
        return;
    }

    // ファイルの内容を処理
    char buffer[1024];
    while (fgets(buffer, sizeof(buffer), file)) {
        // バッファの内容を処理
        printf("Read: %s", buffer);
    }

    // ファイルを閉じる
    fclose(file);
}

この関数では、ファイルを開く際と閉じる際の両方で適切な処理を行っており、エラー発生時には適切なハンドリングが施されています。

○豆知識2:fcloseとメモリの関係性

fclose関数は、開いたファイルポインタに関連付けられたすべてのメモリリソースを解放する役割を持っています。

ファイルポインタが閉じられると、そのポインタに割り当てられたメモリバッファも自動的に解放されるため、プログラムのメモリ効率が向上します。

不適切にファイルポインタを管理すると、メモリリークにつながり、アプリケーションのパフォーマンスに悪影響を及ぼす可能性があります。

例として、下記のコードスニペットを見てみましょう。

#include <stdio.h>

void safeFileOperation(const char* filename) {
    FILE* file = fopen(filename, "w");
    if (!file) {
        perror("ファイルを開けませんでした");
        return;
    }

    // 何かのデータをファイルに書き込む
    fprintf(file, "Hello, world!\n");

    // ファイルを閉じる
    if (fclose(file) != 0) {
        perror("ファイルを閉じる際にエラーが発生しました");
    }
}

この関数では、ファイル操作を安全に行い、fcloseを使ってリソースを確実に解放しています。

これにより、メモリの無駄遣いを防ぐことができます。

まとめ

この記事では、C++におけるfclose関数の基本的な使い方から応用例、さらには発生し得るエラーやその対処法までを詳しく解説しました。

fclose関数を適切に使用することで、ファイルリソースの管理が効率的になり、プログラムの安定性と効率を向上させることができます。

これらの知識を活用して、より堅牢で信頼性の高いソフトウェア開発を目指しましょう。