
C言語入門|バイナリ入出力の基本:fwriteとfread
文字ではなく、データそのものを扱う
これまでの記事では、
fputc や fputs、fprintf などを使って テキストファイル を読み書きしてきました。
テキストファイルは、人が読める文字を前提とした形式なので、
- 改行コード
- 文字コード
- 書式指定
といったルールを意識する必要がありましたね。
一方で、次のような場面ではどうでしょう。
- 構造体をそのまま保存したい。
- 数値データを高速に読み書きしたい。
- 文字コードや改行を一切気にしたくない。
そんなときに活躍するのが、
サイズ指定で読み書きするバイナリ入出力 です。

サイズ指定で読み書きするという考え方
バイナリ入出力では、
- 文字
- 行
- 書式
といった概念は登場しません。
代わりに使うのは、
- 何バイトのデータを
- いくつ分
という、純粋なサイズ指定 です。
この考え方を実現する関数が、
fwrite と fread です。
fwrite:指定したサイズで書き込む
fwrite は、
メモリ上のデータを、そのままの形でファイルに書き込む関数 です。
書式
size_t fwrite(const void* wp, size_t s, size_t n, FILE* fp)引数の意味
| 引数 | 内容 |
|---|---|
| wp | 書き込むデータの先頭アドレス |
| s | データ1個あたりのバイト数 |
| n | 書き込むデータの個数 |
| fp | 書き込み先ファイルのファイルポインタ |
戻り値
| 値 | 意味 |
|---|---|
| n と同じ | 正常にすべて書き込み成功 |
| n より小さい | 途中で失敗 |
つまり、
s × n バイト分を書き込もうとする
という動作になります。
fread:指定したサイズで読み取る
fread は、
ファイルから指定サイズ分のデータをまとめて読み取る関数 です。
書式
size_t fread(void* rp, size_t s, size_t n, FILE* fp)引数の意味
| 引数 | 内容 |
|---|---|
| rp | 読み取ったデータを格納する領域 |
| s | データ1個あたりのバイト数 |
| n | 読み取るデータの個数 |
| fp | 読み取り元ファイルのファイルポインタ |
戻り値
| 値 | 意味 |
|---|---|
| n と同じ | 正常にすべて読み取り成功 |
| n より小さい | ファイル終端または失敗 |
テキスト系の関数と違い、
EOF を直接扱わない点が特徴です。
fwrite / fread を使ったサンプル例
次の例では、
構造体の配列をバイナリファイルに保存し、
その内容を読み戻して画面に表示します。
サンプルプログラム
プロジェクト名:14-9-1 ソースファイル名: sample14-9-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
double value;
} Data;
int main(void)
{
FILE* fp;
Data out[3] = {
{1, 10.5},
{2, 20.0},
{3, 30.25}
};
Data in[3];
fp = fopen("data.bin", "wb");
if (fp == NULL) {
exit(1);
}
fwrite(out, sizeof(Data), 3, fp);
fclose(fp);
fp = fopen("data.bin", "rb");
if (fp == NULL) {
exit(1);
}
fread(in, sizeof(Data), 3, fp);
fclose(fp);
for (int i = 0; i < 3; i++) {
printf("id=%d value=%.2f\n", in[i].id, in[i].value);
}
return 0;
}このプログラムで起きていること
この処理では、
- 構造体 Data を 3 個まとめて書き込み
- 書き込んだバイト列をそのまま読み取り
- メモリ上で元の構造体として復元
という流れになっています。
文字コードや改行は一切関係なく、
メモリ上の状態を丸ごと保存している
と考えるとイメージしやすいでしょう。
テキスト入出力との違いを整理する
| 項目 | テキスト入出力 | バイナリ入出力 |
|---|---|---|
| 単位 | 文字・行 | バイト |
| 書式指定 | 必要 | 不要 |
| 可読性 | 人が読める | 人は読めない |
| 高速性 | 普通 | 高速 |
| 主な用途 | 設定・CSV | セーブデータ・構造体 |
バイナリ入出力で気をつける点
とても便利な fwrite / fread ですが、注意点もあります。
- 構造体のサイズは環境依存
- CPU や OS が変わると互換性がない場合がある。
- エンディアンの違いが影響することがある。
そのため、
- 同一環境で使うデータ
- 一時的な保存
- 高速処理が必要な場面
に向いている方法だと覚えておきましょう。
ここまでのまとめ
この節のポイントは次のとおりです。
- fwrite / fread はサイズ指定で読み書きする。
- データを文字として解釈しない。
- 構造体や配列をそのまま保存できる。
- 高速だが環境依存の注意が必要
バイナリ入出力を理解すると、
C言語らしい低レベルなデータ操作 が一気に身近になります。
