標準入出力

[C言語] fread関数の使い方 – バイナリファイルの読み込み

fread関数は、C言語でバイナリファイルを読み込む際に使用されます。

形式は以下の通りです:

\[\text{size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);}\]

ptrは読み込んだデータを格納するバッファ、sizeは1つの要素のサイズ、nmembは読み込む要素数、streamはファイルポインタです。

freadは、size * nmembバイトを読み込み、成功した場合に読み込んだ要素数を返します。

バイナリファイルを扱う際は、fopenでファイルを”rb”モードで開く必要があります。

fread関数とは

fread関数は、C言語においてバイナリファイルからデータを読み込むための標準ライブラリ関数です。

この関数は、指定したバッファにデータを一度に読み込むことができ、特に大きなデータを効率的に扱う際に非常に便利です。

freadは、ファイルポインタ、読み込むデータのサイズ、要素数、そしてデータを格納するためのバッファのポインタを引数として受け取ります。

これにより、バイナリ形式で保存されたデータをそのままメモリに読み込むことが可能です。

バイナリファイルは、テキストファイルとは異なり、データがそのままの形式で保存されているため、freadを使用することで、構造体や配列などの複雑なデータ構造を簡単に扱うことができます。

ファイルの読み込みが成功したかどうかは、戻り値を確認することで判断できます。

fread関数の使い方

fread関数の基本的な使用例

fread関数を使用する基本的な例を以下に示します。

この例では、バイナリファイルから整数データを読み込みます。

#include <stdio.h>
int main() {
    FILE *file;
    int data[5]; // 読み込むデータを格納する配列
    // バイナリファイルを読み込みモードでオープン
    file = fopen("data.bin", "rb");
    if (file == NULL) {
        // ファイルオープン失敗時のエラーメッセージ
        perror("ファイルオープンエラー");
        return 1;
    }
    // fread関数を使用してデータを読み込む
    size_t elementsRead = fread(data, sizeof(int), 5, file);
    // 読み込んだデータの数を表示
    printf("読み込んだ要素数: %zu\n", elementsRead);
    // ファイルをクローズ
    fclose(file);
    return 0;
}
読み込んだ要素数: 5

このコードでは、data.binというバイナリファイルから5つの整数を読み込み、読み込んだ要素数を表示します。

バッファの準備とメモリ管理

fread関数を使用する際には、データを格納するためのバッファを準備する必要があります。

バッファは、読み込むデータのサイズに応じて適切に確保する必要があります。

例えば、構造体や配列を読み込む場合、以下のようにメモリを動的に確保することも可能です。

int *buffer = (int *)malloc(sizeof(int) * numElements); // numElementsは読み込む要素数

メモリを確保した後は、使用が終わったら必ずfree関数を使ってメモリを解放することが重要です。

これにより、メモリリークを防ぐことができます。

読み込むデータサイズの計算方法

fread関数を使用する際には、読み込むデータのサイズを正確に計算する必要があります。

データのサイズは、以下のように計算できます。

  • 構造体の場合: sizeof(構造体名)を使用
  • 配列の場合: sizeof(配列名[0]) * 要素数を使用

例えば、構造体Personがある場合、次のようにサイズを計算できます。

size_t size = sizeof(Person); // Person構造体のサイズ

fread関数の戻り値の確認方法

fread関数は、実際に読み込んだ要素数を戻り値として返します。

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

例えば、期待した要素数と戻り値を比較することで、エラーを検出できます。

if (elementsRead < expectedElements) {
    // 読み込みエラー処理
    printf("読み込みエラー: 期待した要素数と異なります。\n");
}

このように、fread関数の戻り値を適切に確認することで、プログラムの信頼性を向上させることができます。

バイナリファイルの読み込みの具体例

構造体をバイナリファイルから読み込む

構造体をバイナリファイルから読み込む際には、まず構造体を定義し、その後fread関数を使用してデータを読み込みます。

以下は、Personという構造体をバイナリファイルから読み込む例です。

#include <stdio.h>
#include <stdlib.h>
typedef struct {
    char name[50]; // 名前
    int age;       // 年齢
} Person;
int main() {
    FILE *file;
    Person person; // 読み込む構造体のインスタンス
    // バイナリファイルを読み込みモードでオープン
    file = fopen("people.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    // fread関数を使用して構造体を読み込む
    size_t elementsRead = fread(&person, sizeof(Person), 1, file);
    // 読み込んだ要素数を表示
    printf("読み込んだ要素数: %zu\n", elementsRead);
    printf("名前: %s, 年齢: %d\n", person.name, person.age);
    // ファイルをクローズ
    fclose(file);
    return 0;
}
読み込んだ要素数: 1
名前: 山田太郎, 年齢: 30

このコードでは、people.binというバイナリファイルから1つのPerson構造体を読み込み、その内容を表示します。

配列データをバイナリファイルから読み込む

配列データをバイナリファイルから読み込む場合も、fread関数を使用します。

以下は、整数の配列を読み込む例です。

#include <stdio.h>
#include <stdlib.h>
int main() {
    FILE *file;
    int data[5]; // 読み込む整数の配列
    // バイナリファイルを読み込みモードでオープン
    file = fopen("numbers.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    // fread関数を使用して配列を読み込む
    size_t elementsRead = fread(data, sizeof(int), 5, file);
    // 読み込んだ要素数を表示
    printf("読み込んだ要素数: %zu\n", elementsRead);
    for (size_t i = 0; i < elementsRead; i++) {
        printf("data[%zu]: %d\n", i, data[i]);
    }
    // ファイルをクローズ
    fclose(file);
    return 0;
}
読み込んだ要素数: 5
data[0]: 1
data[1]: 2
data[2]: 3
data[3]: 4
data[4]: 5

このコードでは、numbers.binというバイナリファイルから5つの整数を読み込み、その内容を表示します。

ファイルの終端に達した場合の処理

ファイルの終端に達した場合、fread関数は読み込んだ要素数が期待した数よりも少なくなります。

これを確認するためには、feof関数を使用します。

以下はその例です。

#include <stdio.h>
#include <stdlib.h>
int main() {
    FILE *file;
    int data[5]; // 読み込む整数の配列
    // バイナリファイルを読み込みモードでオープン
    file = fopen("numbers.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    // fread関数を使用して配列を読み込む
    size_t elementsRead = fread(data, sizeof(int), 5, file);
    // 読み込んだ要素数を表示
    printf("読み込んだ要素数: %zu\n", elementsRead);
    // ファイルの終端に達したかどうかを確認
    if (feof(file)) {
        printf("ファイルの終端に達しました。\n");
    }
    // ファイルをクローズ
    fclose(file);
    return 0;
}
読み込んだ要素数: 3
ファイルの終端に達しました。

このコードでは、ファイルの終端に達した場合の処理を示しています。

freadとfwriteを組み合わせたファイル操作

freadfwriteを組み合わせることで、バイナリファイルの読み書きを行うことができます。

以下は、データを読み込んで別のファイルに書き込む例です。

#include <stdio.h>
#include <stdlib.h>
typedef struct {
    char name[50]; // 名前
    int age;       // 年齢
} Person;
int main() {
    FILE *inputFile, *outputFile;
    Person person;
    // 入力ファイルをオープン
    inputFile = fopen("people.bin", "rb");
    if (inputFile == NULL) {
        perror("入力ファイルオープンエラー");
        return 1;
    }
    // 出力ファイルをオープン
    outputFile = fopen("output.bin", "wb");
    if (outputFile == NULL) {
        perror("出力ファイルオープンエラー");
        fclose(inputFile);
        return 1;
    }
    // freadでデータを読み込み、fwriteで別のファイルに書き込む
    while (fread(&person, sizeof(Person), 1, inputFile) == 1) {
        fwrite(&person, sizeof(Person), 1, outputFile);
    }
    // ファイルをクローズ
    fclose(inputFile);
    fclose(outputFile);
    return 0;
}

このコードでは、people.binからPerson構造体を読み込み、output.binに書き込む処理を行っています。

freadfwriteを組み合わせることで、データの移動が簡単に行えます。

fread関数の応用例

大きなファイルを分割して読み込む方法

大きなファイルを分割して読み込む場合、fread関数を使用して一定のサイズごとにデータを読み込むことができます。

以下は、1MBごとにデータを読み込む例です。

#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 1024 * 1024 // 1MB
int main() {
    FILE *file;
    char buffer[BUFFER_SIZE]; // 読み込むためのバッファ
    // 大きなバイナリファイルをオープン
    file = fopen("largefile.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    size_t bytesRead;
    while ((bytesRead = fread(buffer, 1, BUFFER_SIZE, file)) > 0) {
        // 読み込んだデータの処理
        printf("読み込んだバイト数: %zu\n", bytesRead);
    }
    // ファイルをクローズ
    fclose(file);
    return 0;
}

このコードでは、largefile.binという大きなファイルを1MBずつ読み込み、そのバイト数を表示します。

ファイルの一部だけを読み込む方法

ファイルの特定の部分だけを読み込むには、fseek関数を使用してファイルポインタを移動させ、その後freadを使用します。

以下は、ファイルの中間からデータを読み込む例です。

#include <stdio.h>
#include <stdlib.h>
int main() {
    FILE *file;
    char buffer[100]; // 読み込むためのバッファ
    // バイナリファイルをオープン
    file = fopen("data.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    // ファイルポインタを100バイト目に移動
    fseek(file, 100, SEEK_SET);
    // fread関数を使用してデータを読み込む
    size_t bytesRead = fread(buffer, 1, sizeof(buffer), file);
    printf("読み込んだバイト数: %zu\n", bytesRead);
    // ファイルをクローズ
    fclose(file);
    return 0;
}

このコードでは、data.binの100バイト目からデータを読み込み、そのバイト数を表示します。

ファイルの先頭から特定の位置までスキップして読み込む

ファイルの先頭から特定の位置までスキップして読み込む場合も、fseek関数を使用します。

以下は、最初の50バイトをスキップしてからデータを読み込む例です。

#include <stdio.h>
#include <stdlib.h>
int main() {
    FILE *file;
    char buffer[50]; // 読み込むためのバッファ
    // バイナリファイルをオープン
    file = fopen("data.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    // 最初の50バイトをスキップ
    fseek(file, 50, SEEK_SET);
    // fread関数を使用してデータを読み込む
    size_t bytesRead = fread(buffer, 1, sizeof(buffer), file);
    printf("読み込んだバイト数: %zu\n", bytesRead);
    // ファイルをクローズ
    fclose(file);
    return 0;
}

このコードでは、data.binの最初の50バイトをスキップし、その後のデータを読み込みます。

バイナリファイルの内容をテキスト形式に変換する

バイナリファイルの内容をテキスト形式に変換するには、freadでデータを読み込み、fprintfを使用してテキストファイルに書き込むことができます。

以下は、バイナリファイルの内容をテキストファイルに変換する例です。

#include <stdio.h>
#include <stdlib.h>
typedef struct {
    char name[50]; // 名前
    int age;       // 年齢
} Person;
int main() {
    FILE *inputFile, *outputFile;
    Person person;
    // 入力バイナリファイルをオープン
    inputFile = fopen("people.bin", "rb");
    if (inputFile == NULL) {
        perror("入力ファイルオープンエラー");
        return 1;
    }
    // 出力テキストファイルをオープン
    outputFile = fopen("output.txt", "w");
    if (outputFile == NULL) {
        perror("出力ファイルオープンエラー");
        fclose(inputFile);
        return 1;
    }
    // freadでデータを読み込み、fprintfでテキストファイルに書き込む
    while (fread(&person, sizeof(Person), 1, inputFile) == 1) {
        fprintf(outputFile, "名前: %s, 年齢: %d\n", person.name, person.age);
    }
    // ファイルをクローズ
    fclose(inputFile);
    fclose(outputFile);
    return 0;
}

このコードでは、people.binからPerson構造体を読み込み、その内容をoutput.txtにテキスト形式で書き込む処理を行っています。

バイナリデータをテキスト形式に変換することで、データの可読性を向上させることができます。

fread関数のエラーハンドリング

fread関数が失敗する場合の原因

fread関数が失敗する主な原因はいくつかあります。

以下に代表的な原因を示します。

原因説明
ファイルがオープンされていないfopen関数でファイルが正しくオープンされていない場合。
読み込むデータが不足しているファイルの終端に達している場合や、ファイルサイズが小さい場合。
メモリ不足読み込むためのバッファが十分に確保されていない場合。
読み込み権限がないファイルに対する読み込み権限がない場合。

これらの原因を考慮し、適切なエラーハンドリングを行うことが重要です。

feof関数とferror関数の使い方

feof関数ferror関数は、ファイル操作におけるエラーチェックに役立ちます。

  • feof関数: ファイルの終端に達したかどうかを確認します。

戻り値が非ゼロの場合、ファイルの終端に達しています。

  • ferror関数: ファイル操作中にエラーが発生したかどうかを確認します。

戻り値が非ゼロの場合、エラーが発生しています。

以下は、これらの関数を使用した例です。

#include <stdio.h>
#include <stdlib.h>
int main() {
    FILE *file;
    int data[5];
    // バイナリファイルをオープン
    file = fopen("data.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    // fread関数を使用してデータを読み込む
    size_t elementsRead = fread(data, sizeof(int), 5, file);
    // 読み込みエラーのチェック
    if (ferror(file)) {
        perror("読み込みエラー");
    } else if (feof(file)) {
        printf("ファイルの終端に達しました。\n");
    } else {
        printf("読み込んだ要素数: %zu\n", elementsRead);
    }
    // ファイルをクローズ
    fclose(file);
    return 0;
}

このコードでは、freadの後にfeofferrorを使用して、読み込みの結果を確認しています。

エラー発生時のリトライ処理

エラーが発生した場合、リトライ処理を行うことで、読み込みを再試行することができます。

以下は、freadのリトライ処理の例です。

#include <stdio.h>
#include <stdlib.h>
#define MAX_RETRIES 3 // 最大リトライ回数
int main() {
    FILE *file;
    int data[5];
    int retries = 0;
    // バイナリファイルをオープン
    file = fopen("data.bin", "rb");
    if (file == NULL) {
        perror("ファイルオープンエラー");
        return 1;
    }
    // リトライ処理
    while (retries < MAX_RETRIES) {
        size_t elementsRead = fread(data, sizeof(int), 5, file);
        // 読み込みエラーのチェック
        if (ferror(file)) {
            perror("読み込みエラー。リトライします。");
            clearerr(file); // エラー状態をクリア
            retries++;
        } else {
            printf("読み込んだ要素数: %zu\n", elementsRead);
            break; // 成功した場合はループを抜ける
        }
    }
    if (retries == MAX_RETRIES) {
        printf("最大リトライ回数に達しました。処理を終了します。\n");
    }
    // ファイルをクローズ
    fclose(file);
    return 0;
}

このコードでは、freadが失敗した場合に最大3回までリトライを行い、成功した場合は読み込んだ要素数を表示します。

リトライ処理を行うことで、一時的なエラーに対処することができます。

まとめ

この記事では、C言語fread関数を使用してバイナリファイルを読み込む方法について詳しく解説しました。

具体的には、fread関数の基本的な使い方から、構造体や配列データの読み込み、エラーハンドリングの方法まで幅広く取り上げました。

これを機に、バイナリファイルの操作に挑戦し、実際のプログラムに応用してみてください。

関連記事

Back to top button