【6日でできるC言語入門】バイナリファイルの読み書き

C言語では、「バイナリファイルの読み書き」はテキストファイル以上に幅広い用途で使われます。
画像データや実行ファイル、設定ファイル、独自のデータ形式など、人間が直接読めないデータも効率よく保存・読み込みできます。
ここでは、バイナリファイル操作の基礎から実践的なテクニックまで、サンプルプログラムや関数の使い方を詳しく解説します。

1.バイナリファイルの基本的な読み書き

1.1. バイナリファイルへの書き込み

バイナリファイルは、テキストファイルとは異なり"wb"(書き込み)や"rb"(読み込み)モードで開きます。
データの書き込みにはfwrite関数を使います。

関数書式主な用途
fopenFILE* fopen("ファイル名", "wb");バイナリ書き込みでファイルを開く
fwritesize_t fwrite(データ, 1要素の大きさ, 要素数, FILE* fp);バイナリデータを書き込む
fcloseint fclose(FILE* fp);ファイルを閉じる

サンプルプログラム(バイナリ書き込み+読み込み)

プロジェクト/ファイル名: Lesson68_1/main.c

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

int main(void) {
    FILE* fp;
    unsigned char wdata[] = { 0xAA, 0xBB, 0xCC, 0xDD }; // 書き込むデータ
    unsigned char rdata[4];

    // バイナリ書き込み
    fp = fopen("testdata.bin", "wb");
    if (fp == NULL) {
        printf("ファイルの書き込みオープンに失敗しました。\n");
        return 1;
    }
    fwrite(wdata, sizeof(unsigned char), 4, fp);
    fclose(fp);

    // バイナリ読み込み
    fp = fopen("testdata.bin", "rb");
    if (fp == NULL) {
        printf("ファイルの読み込みオープンに失敗しました。\n");
        return 1;
    }
    fread(rdata, sizeof(unsigned char), 4, fp);
    fclose(fp);

    // 読み込んだ内容の表示
    for (int i = 0; i < 4; i++) {
        printf("%02X ", rdata[i]);
    }
    printf("\n");
    return 0;
}

実行結果

「SDLチェック」を「いいえ」にして、プログラムを実行します。

AA BB CC DD

1.2. バイナリファイル専用の関数

関数説明
fwriteデータをバイナリ形式でファイルに書き込む。
freadファイルからバイナリ形式で読み込む。
fseekファイルの読み書き位置を移動する。
ftell現在の読み書き位置(バイト単位)を得る。

2.ファイルサイズが不明な場合の読み込み

2.1. ファイルサイズの取得と動的メモリ確保

 バイナリファイルはサイズが可変のことが多いので、fseekftellでファイルサイズを調べてからメモリを動的確保するのが一般的です。

サンプルプログラム(ファイルサイズに応じて動的読み込み)

プロジェクト/ファイル名: Lesson68_2/main.c

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

int main(void) {
    FILE* fp;
    long filesize;
    unsigned char* buffer;

    // ファイルをバイナリ読み込みで開く
    fp = fopen("testdata.bin", "rb");
    if (fp == NULL) {
        printf("ファイルオープンに失敗しました。\n");
        return 1;
    }

    // ファイルサイズ取得
    fseek(fp, 0, SEEK_END);
    filesize = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    // バッファの動的確保
    buffer = (unsigned char*)malloc(filesize);
    if (buffer == NULL) {
        printf("メモリ確保に失敗しました。\n");
        fclose(fp);
        return 1;
    }

    fread(buffer, 1, filesize, fp);
    fclose(fp);

    // バイナリ内容の表示
    for (long i = 0; i < filesize; i++) {
        printf("%02X ", buffer[i]);
    }
    printf("\n");

    free(buffer);
    return 0;
}

実行結果

 「Lesson68_2」ディレクトリに、先ほど作成した「testdata.bin」をコピーして、プロジェクトのリソースファイルに登録しておきます。

「SDLチェック」を「いいえ」にして、プログラムを実行します。

AA BB CC DD

3.各関数の詳細解説と注意点

3.1. fwrite関数/fread関数

関数書式概要
fwritefwrite(配列, 要素サイズ, 要素数, FILE*)配列内容をバイナリでファイルに保存
freadfread(配列, 要素サイズ, 要素数, FILE*)ファイル内容を配列に読み込む
  • 構造体や配列もバイナリで直接読み書き可能
  • 要素サイズ×要素数が実際のバイト数

3.2. fseek関数/ftell関数

関数書式主な用途
fseekfseek(FILE*, 移動バイト数, 開始位置);ファイルポインタ移動
ftelllong ftell(FILE*);現在位置をバイト数で返す
開始位置の定数意味
SEEK_SETファイル先頭
SEEK_CUR現在位置
SEEK_ENDファイル末尾

まとめ

  • バイナリファイルは"wb","rb"モード+fwrite,freadで効率的に扱える
  • ファイルサイズが不明な場合はfseekftellで取得して動的確保
  • テキストファイルと異なり「バイト単位」でデータの保存・読取が可能

バイナリファイルを使いこなすことで、C言語のデータ入出力は一層パワフルになります!