[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を組み合わせたファイル操作
fread
とfwrite
を組み合わせることで、バイナリファイルの読み書きを行うことができます。
以下は、データを読み込んで別のファイルに書き込む例です。
#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
に書き込む処理を行っています。
fread
とfwrite
を組み合わせることで、データの移動が簡単に行えます。
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
の後にfeof
とferror
を使用して、読み込みの結果を確認しています。
エラー発生時のリトライ処理
エラーが発生した場合、リトライ処理を行うことで、読み込みを再試行することができます。
以下は、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関数
の基本的な使い方から、構造体や配列データの読み込み、エラーハンドリングの方法まで幅広く取り上げました。
これを機に、バイナリファイルの操作に挑戦し、実際のプログラムに応用してみてください。