C言語のfprintf関数を徹底解説|初心者から中級者までの完全ガイド

目次

1. fprintf関数とは

fprintfの基本概要

fprintf関数は、C言語で使用される標準的な入出力関数の一つです。この関数の主な役割は、「フォーマット付きで文字列を出力する」ことです。fprintfを使用することで、指定したフォーマットに従い、データを整形して出力先に書き込むことが可能です。

一般的に、fprintfは以下のような場面で活用されます。

  • ログファイルの作成: プログラムの実行履歴やエラー情報を記録する。
  • フォーマット付きデータの保存: 数値や文字列を、決まった形式でファイルに保存する。
  • デバッグ情報の出力: 開発中のプログラムの動作を確認するためのデータ出力。

fprintfの基本構文

int fprintf(FILE *stream, const char *format, ...);

構文の各部分

  • FILE *stream: 書き込み先を指定します。例えば、標準出力(stdout)やファイル(fopenで開いたファイル)です。
  • const char *format: 出力フォーマットを指定する文字列です。これはprintf関数と同じ形式で記述します。
  • ...: 可変長引数を使って、出力するデータを指定します。

戻り値は、正常に書き込まれた文字数(正の整数)です。エラーが発生した場合は-1を返します。

他の関数との比較

fprintfと類似する関数として、printfsprintfがあります。それぞれの違いを以下にまとめます。

printfとの違い

printfは標準出力(通常はコンソール)にデータを出力するために使われます。一方で、fprintfは出力先を指定することができ、柔軟性があります。

例: printfの使用

printf("Hello, World!\n");

これは常にコンソールに出力されます。

例: fprintfの使用

FILE *file = fopen("output.txt", "w");
fprintf(file, "Hello, World!\n");
fclose(file);

この場合、出力は指定したファイル(output.txt)に書き込まれます。

sprintfとの違い

sprintfは、出力先が「文字列」である点が異なります。つまり、書き込み先がメモリ内のバッファになります。

例: sprintfの使用

char buffer[50];
sprintf(buffer, "The result is %d", 42);

この場合、文字列"The result is 42"bufferに書き込まれます。

まとめ

  • fprintfは、ファイルや標準出力など、柔軟に出力先を指定できる便利な関数です。
  • 他の出力関数(printfsprintf)と使い分けることで、プログラムの効率や可読性を高めることが可能です。

2. fprintfの基本的な使い方

シンタックスと基本的な引数の説明

fprintf関数は、データをフォーマット付きで出力するための柔軟なツールです。その基本構文は以下の通りです。

int fprintf(FILE *stream, const char *format, ...);

以下に、引数の詳細を説明します。

  1. FILE *stream
  • 書き込み先を指定します。
  • 一般的な選択肢:
    • 標準出力(stdout
    • 標準エラー出力(stderr
    • ファイル(fopen関数で開いたファイル)
  1. const char *format
  • 出力フォーマットを定義します。
  • フォーマット指定子を使って、文字列、整数、浮動小数点数などの形式を指定できます(例: %s, %d, %f)。
  1. 可変長引数(…)
  • フォーマット指定子に対応するデータを提供します。
  • 例: フォーマットが"Name: %s, Age: %d"の場合、対応するデータとして名前と年齢を渡します。

戻り値として、正常に書き込まれた文字数(正の整数)が返されます。エラーが発生した場合は-1を返します。

基本的なコード例

以下は、fprintfを使用した簡単な例を示します。

標準出力への出力

標準出力(stdout)に文字列をフォーマット付きで出力します。

#include <stdio.h>

int main() {
    fprintf(stdout, "Hello, %s! You have %d new messages.\n", "Alice", 5);
    return 0;
}

出力結果:

Hello, Alice! You have 5 new messages.

この例では、標準出力としてstdoutを明示的に指定しています。

ファイルへの出力

ファイルにデータを書き込む際にfprintfを使用します。

#include <stdio.h>

int main() {
    FILE *file = fopen("output.txt", "w"); // ファイルを「書き込みモード」で開く
    if (file == NULL) {
        fprintf(stderr, "Error opening file.\n");
        return 1;
    }

    fprintf(file, "Name: %s, Age: %d\n", "Bob", 30);
    fclose(file); // ファイルを閉じる
    return 0;
}

output.txt の内容:

Name: Bob, Age: 30

書式指定子の基礎

fprintfでは、フォーマット指定子を使用して、出力の形式を柔軟にコントロールできます。以下は基本的な指定子の例です。

指定子説明
%d10進数の整数42
%f浮動小数点数3.141593
%s文字列"Hello"
%c単一の文字'A'
%x16進数(小文字)0x2a
%o8進数052

例:

fprintf(stdout, "Integer: %d, Float: %.2f, String: %s\n", 10, 3.14, "Test");

出力結果:

Integer: 10, Float: 3.14, String: Test
侍エンジニア塾

3. fprintfでの書式指定の活用

幅(Minimum Width)

幅を指定すると、出力文字数が指定した幅に満たない場合にスペースで埋められます。

例:

fprintf(stdout, "|%10s|\n", "Hello");
fprintf(stdout, "|%10d|\n", 123);

出力結果:

|     Hello|
|       123|

ここでは、幅を10に指定しています。文字数が足りない場合、左側にスペースが挿入されます。


精度(Precision)

精度は、以下の用途に応じて異なる意味を持ちます。

  • 文字列(%s): 出力する最大文字数。
  • 浮動小数点数(%f, %e, %g): 小数点以下の桁数。

例:

fprintf(stdout, "%.3f\n", 3.141592); // 浮動小数点数の精度
fprintf(stdout, "%.5s\n", "Hello, World!"); // 文字列の最大長

出力結果:

3.142
Hello

フラグ

フラグを使うと、出力の配置や形式を制御できます。

フラグ説明
-左揃え(デフォルトは右揃え)|%-10s||Hello |
+数値の符号を常に表示(正数でも+を表示)%+d+42
0ゼロ埋め(幅指定時に有効)%05d00042
#特定の型で形式指定(16進数や8進数)%#x0x2a
正の数値の先頭にスペースを挿入% d42

例:

fprintf(stdout, "|%-10s|%+05d|%#x|\n", "Left", 42, 42);

出力結果:

|Left      |+0042|0x2a|

実践的な応用例

fprintfの幅、精度、フラグを組み合わせることで、フォーマットされた表形式のデータを作成することができます。

表形式のデータ出力

以下は、学生の成績をフォーマット付きで出力する例です。

#include <stdio.h>

int main() {
    fprintf(stdout, "|%-10s|%5s|%5s|%5s|\n", "Name", "Math", "Eng", "Sci");
    fprintf(stdout, "|%-10s|%5d|%5d|%5d|\n", "Alice", 95, 88, 92);
    fprintf(stdout, "|%-10s|%5d|%5d|%5d|\n", "Bob", 82, 79, 85);
    return 0;
}

出力結果:

|Name      | Math|  Eng|  Sci|
|Alice     |   95|   88|   92|
|Bob       |   82|   79|   85|

数値データの整形

特定の数値をフォーマット付きで出力し、統一された見た目にします。

例:

fprintf(stdout, "Price: $%8.2f\n", 1234.5);
fprintf(stdout, "Discount: %06d%%\n", 25);

出力結果:

Price: $ 1234.50
Discount: 000025%

注意点

  1. 不正なフォーマット指定子
  • フォーマット指定子とデータ型が一致しない場合、予期しない出力やエラーが発生します。
  • 例: %dに文字列を渡すと未定義動作になる可能性があります。
  1. 幅や精度の指定
  • 過剰に大きい幅を指定すると、出力が冗長になり、リソースを無駄にする場合があります。

まとめ

  • 幅、精度、フラグを活用することで、fprintfの出力を細かく制御可能です。
  • 表形式データや数値整形を効果的に行うことで、プログラムの出力を見やすくできます。
  • フォーマット指定子と渡すデータ型の一致に注意することで、安全な出力が実現します。

4. ファイル操作とfprintf

ファイルを開く方法(fopen)

fprintfを使用してファイルにデータを書き込むためには、まずファイルを開く必要があります。C言語では、fopen関数を使ってファイルを開きます。

fopenの基本構文

FILE *fopen(const char *filename, const char *mode);
引数の説明
  • filename: 開きたいファイルの名前(パス)。
  • mode: ファイルを開くモードを指定する文字列。
  • "r": 読み込み専用
  • "w": 書き込み専用(既存ファイルは上書き)
  • "a": 追記専用(ファイルの末尾に追加)
  • "rb"/"wb"/"ab": バイナリモードでの操作(r/w/aと組み合わせ)

戻り値

  • ファイルが正常に開けた場合、FILE型ポインタを返します。
  • 失敗した場合、NULLを返します。

fopenの使用例

#include <stdio.h>

int main() {
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    fprintf(file, "Hello, World!\n");
    fclose(file);
    return 0;
}

このプログラムは、example.txtというファイルを開き、内容を書き込んでから閉じます。

fprintfを使ったファイル書き込み

fprintfを使用することで、開いたファイルにフォーマット付きでデータを書き込むことができます。以下に、いくつかのシナリオでの使用例を示します。

基本的なファイル書き込み

#include <stdio.h>

int main() {
    FILE *file = fopen("data.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    fprintf(file, "Name: %s, Age: %d\n", "Alice", 25);
    fprintf(file, "Name: %s, Age: %d\n", "Bob", 30);

    fclose(file);
    return 0;
}

data.txt の内容:

Name: Alice, Age: 25
Name: Bob, Age: 30

CSVファイルの作成

CSV(Comma-Separated Values)形式のデータを書き込む例です。

#include <stdio.h>

int main() {
    FILE *file = fopen("students.csv", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    // ヘッダー行
    fprintf(file, "Name,Math,English,Science\n");

    // データ行
    fprintf(file, "Alice,95,88,92\n");
    fprintf(file, "Bob,82,79,85\n");

    fclose(file);
    return 0;
}

students.csv の内容:

Name,Math,English,Science
Alice,95,88,92
Bob,82,79,85

ファイルを閉じる(fclose)

ファイル操作が終わったら、fclose関数を使用してファイルを閉じる必要があります。これを行わないと、以下の問題が発生する可能性があります。

  • ファイルへのデータ書き込みが完全に行われない。
  • システムリソースが無駄に消費される。

fcloseの基本構文

int fclose(FILE *stream);

戻り値

  • 成功した場合は0
  • 失敗した場合はEOF(エンド・オブ・ファイル)を返します。

fcloseの例

FILE *file = fopen("example.txt", "w");
if (file != NULL) {
    fprintf(file, "This is a test.\n");
    fclose(file);
}

安全なファイル操作のヒント

  1. ファイルポインタの確認
  • fopenの戻り値がNULLかどうかを常に確認する。
  1. ファイル閉じ忘れ防止
  • ファイルを開いたら必ずfcloseを呼び出す。
  1. エラーハンドリング
  • ファイル操作中のエラーを検出して処理する。
  • 例: ディスク容量不足やファイル権限エラー。

まとめ

  • fprintfを使う際には、まずファイルをfopenで開き、処理終了後にfcloseで閉じることが重要です。
  • ファイル操作のモードやエラーハンドリングを適切に行うことで、安全かつ効率的なファイル操作が可能になります。
  • 応用として、CSV形式のデータ保存やログ記録に利用することができます。
年収訴求

5. エラーハンドリング

fprintfの戻り値を使ったエラー処理

fprintfの戻り値を確認することで、書き込み操作が成功したかどうかを判断できます。

戻り値の仕様

  • 正常に書き込まれた場合:書き込まれた文字数(正の整数)を返す。
  • エラーが発生した場合:-1 を返す。

基本的なエラーチェック例

#include <stdio.h>

int main() {
    FILE *file = fopen("output.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    int result = fprintf(file, "Hello, World!\n");
    if (result < 0) {
        fprintf(stderr, "Error: Failed to write to file.\n");
    }

    fclose(file);
    return 0;
}

このプログラムでは、fprintfの戻り値を確認し、書き込みに失敗した場合にエラーメッセージを出力しています。

標準エラー出力(stderr)を活用

stderrは、プログラムがエラーや警告を報告するために使用する標準的な出力ストリームです。stderrにエラーメッセージを出力することで、ユーザーや開発者に問題を明確に伝えることができます。

例: stderrを使ったエラー出力

#include <stdio.h>

int main() {
    FILE *file = fopen("nonexistent_directory/output.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Unable to open file. Check the directory path.\n");
        return 1;
    }

    fclose(file);
    return 0;
}

出力結果(エラー時):

Error: Unable to open file. Check the directory path.

stderrを使用することで、エラー出力を通常の標準出力(stdout)と分離することが可能です。

実践的なエラー処理コード

以下は、ファイル操作における典型的なエラーを処理する実践的な例です。

例: 書き込みとファイルクローズのエラー処理

#include <stdio.h>

int main() {
    FILE *file = fopen("output.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    // 書き込み処理
    if (fprintf(file, "Logging data: %d\n", 42) < 0) {
        fprintf(stderr, "Error: Failed to write to file.\n");
        fclose(file);
        return 1;
    }

    // ファイルクローズ時のエラー確認
    if (fclose(file) != 0) {
        fprintf(stderr, "Error: Failed to close the file.\n");
        return 1;
    }

    printf("File operation completed successfully.\n");
    return 0;
}

ポイント:

  1. ファイルオープン、書き込み、クローズの各ステップでエラーを確認しています。
  2. エラー時には適切なメッセージを出力し、プログラムを終了します。

よくあるエラーと対処法

1. ファイルを開けない

原因:

  • ファイルが存在しない。
  • ディレクトリが間違っている。
  • アクセス権限が不足している。

対処法:

  • ファイルパスを確認する。
  • アクセス権限を修正する。
  • fopenの戻り値を確認する。

2. 書き込みが失敗する

原因:

  • ディスク容量不足。
  • ファイルが読み取り専用として開かれている。

対処法:

  • ファイルのモードを確認する("w""a"を使用)。
  • ディスク容量をチェックする。

3. ファイルクローズ時のエラー

原因:

  • システムリソースが不足している。
  • ハードウェアの不具合。

対処法:

  • クローズ時にエラーを確認する。
  • ファイルを開く際、必要最小限のリソースを使用する。

まとめ

  • fprintfの戻り値を確認することで、書き込みエラーを検出できます。
  • 標準エラー出力(stderr)を使用することで、エラーメッセージを適切に報告可能です。
  • ファイル操作全般でのエラー処理を適切に実装することで、プログラムの信頼性が向上します。

6. 応用例

ログファイルの自動生成

ログファイルは、プログラムの動作状況やエラー情報を記録するために使用されます。以下は、日時を含むログを記録する例です。

例: 日時付きログの出力

#include <stdio.h>
#include <time.h>

int main() {
    FILE *logFile = fopen("log.txt", "a"); // 追記モードで開く
    if (logFile == NULL) {
        fprintf(stderr, "Error: Could not open log file.\n");
        return 1;
    }

    time_t now = time(NULL);
    struct tm *localTime = localtime(&now);

    fprintf(logFile, "[%04d-%02d-%02d %02d:%02d:%02d] Program started\n",
            localTime->tm_year + 1900, localTime->tm_mon + 1, localTime->tm_mday,
            localTime->tm_hour, localTime->tm_min, localTime->tm_sec);

    fclose(logFile);
    return 0;
}

ログファイルの内容:

[2025-01-19 15:45:30] Program started

ポイント

  • time.hを利用して現在の日時を取得しています。
  • 追記モード("a")を使用して、ログをファイルの末尾に追加します。

テーブル形式データの書き込み

データを表形式で整然と出力する例を示します。これは、結果レポートやデータベース情報をエクスポートする場合に役立ちます。

例: 学生の成績表を出力

#include <stdio.h>

int main() {
    FILE *file = fopen("report.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    fprintf(file, "|%-10s|%6s|%6s|%6s|\n", "Name", "Math", "Eng", "Sci");
    fprintf(file, "|%-10s|%6d|%6d|%6d|\n", "Alice", 90, 85, 88);
    fprintf(file, "|%-10s|%6d|%6d|%6d|\n", "Bob", 78, 82, 80);

    fclose(file);
    return 0;
}

report.txtの内容:

|Name      | Math|  Eng|  Sci|
|Alice     |   90|   85|   88|
|Bob       |   78|   82|   80|

ポイント

  • 左揃え(%-10s)や右揃え(%6d)を使用して、見やすい形式を実現しています。

CSVファイルへのデータ保存

CSV(Comma-Separated Values)は、データの保存や他のプログラムとのデータ交換に便利です。

例: データをCSV形式で保存

#include <stdio.h>

int main() {
    FILE *file = fopen("data.csv", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    // ヘッダー行を記録
    fprintf(file, "Name,Math,English,Science\n");

    // データ行を記録
    fprintf(file, "Alice,90,85,88\n");
    fprintf(file, "Bob,78,82,80\n");

    fclose(file);
    return 0;
}

data.csv の内容:

Name,Math,English,Science
Alice,90,85,88
Bob,78,82,80

ポイント

  • 各フィールドをコンマ(,)で区切ることで、他のツール(ExcelやPython)で読み取り可能な形式を作成します。

デバッグ情報の記録

デバッグ用のログを記録することで、プログラムの状態を追跡しやすくなります。

例: 実行時変数の記録

#include <stdio.h>

int main() {
    FILE *debugFile = fopen("debug.log", "w");
    if (debugFile == NULL) {
        fprintf(stderr, "Error: Could not open debug log file.\n");
        return 1;
    }

    int x = 42;
    fprintf(debugFile, "Debug: Variable x = %d\n", x);

    fclose(debugFile);
    return 0;
}

debug.log の内容:

Debug: Variable x = 42

ポイント

  • デバッグ情報をファイルに記録することで、複雑なプログラムの問題を特定しやすくなります。

まとめ

  • fprintfを使用することで、ログファイル、表形式のデータ、CSVファイルなど、多様なデータ保存形式を実現できます。
  • 実務では、日時付きのログやCSV形式が特に役立ちます。
  • 応用例を通じて、より効果的にfprintfを活用できるようになります。

7. よくある質問(FAQ)

1. fprintfとprintfの違いは何ですか?

回答

  • printf:
  • 標準出力(通常はコンソール)にデータを出力します。
  • 出力先を変更することはできません。
  • fprintf:
  • 出力先を自由に指定できます(例: ファイル、標準出力、標準エラー出力など)。
  • より柔軟なデータ出力が可能です。

#include <stdio.h>

int main() {
    printf("This is printed to the console.\n"); // 常に標準出力

    FILE *file = fopen("output.txt", "w");
    if (file != NULL) {
        fprintf(file, "This is written to a file.\n"); // ファイルに出力
        fclose(file);
    }
    return 0;
}

2. fprintfで日本語を正しく出力するには?

回答

  • 日本語を正しく出力するためには、以下の点を確認する必要があります。
  1. 文字コード:
    • 使用する環境に応じて、適切な文字コード(例: UTF-8, Shift-JIS)を設定する。
  2. ファイルのエンコーディング:
    • 書き込むファイルのエンコーディングを文字コードに合わせる。

例: UTF-8で日本語を出力

#include <stdio.h>
#include <locale.h>

int main() {
    setlocale(LC_ALL, ""); // ロケールを設定

    FILE *file = fopen("japanese.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    fprintf(file, "こんにちは、世界!\n");
    fclose(file);
    return 0;
}

注意:

  • 環境によっては、文字化けを防ぐためにエンコーディングを明示的に設定する必要があります(例: WindowsでShift-JISを使用)。

3. fprintfでエラーが発生する主な原因は?

回答

  • 主なエラー原因には以下が挙げられます。
  1. ファイルが開けない:
    • ファイルパスが間違っている。
    • アクセス権限が不足している。
  2. ディスク容量不足:
    • 書き込み中に空き容量が足りなくなる。
  3. フォーマット指定子の不一致:
    • データ型とフォーマット指定子が一致していない。

例: フォーマット指定子の不一致

#include <stdio.h>

int main() {
    FILE *file = fopen("error.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    // フォーマット指定子に文字列を期待しているが、整数を渡している
    fprintf(file, "%s", 42); // エラー発生
    fclose(file);
    return 0;
}

対策:

  • フォーマット指定子と渡すデータ型を確認してください(例: %dは整数、%sは文字列)。

4. fprintfでのバッファリングの影響は?

回答

  • バッファリング:
  • 出力は一時的にバッファに保存され、バッファが満杯になるかfclosefflushが呼び出されるまでファイルに書き込まれません。
  • 問題点:
  • プログラムが異常終了した場合、バッファに溜まっているデータがファイルに書き込まれずに失われる可能性があります。

対策

  1. fflushを使用:
  • バッファを手動でフラッシュすることで、データを即座に書き込む。
  1. 例: fflushの使用
#include <stdio.h>

int main() {
    FILE *file = fopen("buffered_output.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    fprintf(file, "Buffered data.\n");
    fflush(file); // バッファをフラッシュして即座に書き込み

    fclose(file);
    return 0;
}

5. ファイル出力が途中で途切れる場合の対処法は?

回答

  • ファイル出力が途中で途切れる原因として以下が考えられます。
  1. ファイルを閉じていない:
    • バッファがフラッシュされず、未書き込みのデータが失われる。
  2. ディスク容量不足:
    • 書き込み中に空き容量が足りなくなる。

例: ファイルを正しく閉じる

#include <stdio.h>

int main() {
    FILE *file = fopen("partial_output.txt", "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open file.\n");
        return 1;
    }

    fprintf(file, "This is complete data.\n");

    // fcloseを忘れない
    fclose(file);
    return 0;
}

対策:

  • fcloseを必ず呼び出し、出力処理を正確に終了させる。
  • 書き込み中にエラーが発生した場合は、戻り値を確認する。

まとめ

  • fprintfは柔軟性の高い出力関数ですが、適切なエラーハンドリングや文字コードの設定が重要です。
  • FAQで取り上げた内容を参考にすることで、よくあるトラブルを未然に防ぐことができます。

8. 複数ファイルの同時出力

fprintfを活用すれば、複数のファイルに同時にデータを書き込むことができます。このセクションでは、実務で役立つ同時出力の方法を解説します。

複数のファイルを同時に扱う基本構造

C言語では、複数のFILEポインタを使用して、複数のファイルを同時に操作できます。それぞれのファイルポインタに対してfopenfprintffcloseを適切に実行することが重要です。

基本例: 2つのファイルに同時出力

#include <stdio.h>

int main() {
    // 2つのファイルを開く
    FILE *file1 = fopen("output1.txt", "w");
    FILE *file2 = fopen("output2.txt", "w");

    if (file1 == NULL || file2 == NULL) {
        fprintf(stderr, "Error: Could not open one of the files.\n");
        if (file1) fclose(file1);
        if (file2) fclose(file2);
        return 1;
    }

    // ファイル1にデータを書き込む
    fprintf(file1, "This is the first file.\n");

    // ファイル2にデータを書き込む
    fprintf(file2, "This is the second file.\n");

    // ファイルを閉じる
    fclose(file1);
    fclose(file2);

    printf("Data written to both files successfully.\n");
    return 0;
}

output1.txt の内容:

This is the first file.

output2.txt の内容:

This is the second file.

ポイント

  1. エラーチェック:
  • それぞれのfopenが成功したかを確認します。
  1. リソースの解放:
  • 必ず開いた全てのファイルをfcloseで閉じる。

動的なファイル操作

動的にファイル名を生成し、複数のファイルにデータを書き込む例を示します。

例: 動的ファイル名を使用した出力

#include <stdio.h>

int main() {
    char filename[20];
    for (int i = 1; i <= 3; i++) {
        // ファイル名を動的に生成
        sprintf(filename, "file%d.txt", i);

        // ファイルを開く
        FILE *file = fopen(filename, "w");
        if (file == NULL) {
            fprintf(stderr, "Error: Could not open %s\n", filename);
            continue; // 次のファイルに進む
        }

        // ファイルに書き込む
        fprintf(file, "This is file number %d\n", i);

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

    printf("Data written to files successfully.\n");
    return 0;
}

生成されるファイルの例:

  • file1.txt: This is file number 1
  • file2.txt: This is file number 2
  • file3.txt: This is file number 3

ポイント

  • sprintfを使用してファイル名を動的に生成。
  • エラーが発生した場合は次のループに進む。

複数ファイルへの並列書き込み

複数のファイルに同時に大量のデータを書き込む場合、並列処理(スレッド)を使用することができます。

例: スレッドを使用した並列書き込み

以下は、POSIXスレッド(pthread)を使用して並列書き込みを行う例です。

#include <stdio.h>
#include <pthread.h>

void *write_to_file(void *arg) {
    char *filename = (char *)arg;
    FILE *file = fopen(filename, "w");
    if (file == NULL) {
        fprintf(stderr, "Error: Could not open %s\n", filename);
        return NULL;
    }

    fprintf(file, "Data written to %s\n", filename);
    fclose(file);
    return NULL;
}

int main() {
    pthread_t threads[3];
    char *filenames[] = {"thread1.txt", "thread2.txt", "thread3.txt"};

    for (int i = 0; i < 3; i++) {
        pthread_create(&threads[i], NULL, write_to_file, filenames[i]);
    }

    for (int i = 0; i < 3; i++) {
        pthread_join(threads[i], NULL);
    }

    printf("Data written to all files in parallel.\n");
    return 0;
}

生成されるファイルの例:

  • thread1.txt: Data written to thread1.txt
  • thread2.txt: Data written to thread2.txt
  • thread3.txt: Data written to thread3.txt

ポイント

  • スレッドを使用することで、複数のファイルに並列で書き込みが可能。
  • スレッドの同期(pthread_join)を忘れない。

まとめ

  • fprintfを使えば、複数のファイルに同時にデータを出力可能。
  • 動的なファイル名生成やスレッドを活用することで、柔軟性やパフォーマンスが向上します。
  • リソース管理(fcloseやエラー処理)を徹底することで、安全なプログラムを実現できます。

9. 参考リンク