言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

C言語辞典

  1. トップページ
  2. C言語辞典
  3. fread() / fwrite()

fread() / fwrite()

対応: C89(1989)

バイナリデータをファイルへ直接読み書きする関数です。テキストモードと異なり改行変換を行わないため、画像・音声・構造体データなどのバイナリファイルを正確に扱えます。

構文

// バイナリデータをファイルから読み込みます。
// 戻り値: 読み込んだブロック数(feof() や ferror() で確認します)。
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);

// バイナリデータをファイルへ書き込みます。
// 戻り値: 書き込んだブロック数(count と異なる場合はエラーです)。
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);

引数一覧

引数概要
ptrデータを格納するバッファ(読み込み先)またはデータの先頭アドレス(書き込み元)です。
size1ブロックのバイト数です。構造体なら『sizeof(struct X)』を渡します。
count読み書きするブロック数です。
stream『"rb"』または『"wb"』で開いた FILE ポインタです。

サンプルコード

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

typedef struct {
    int id;
    double score;
} Record;

int main(void) {
    // 構造体データをバイナリファイルに書き込みます。
    Record rec = {42, 98.5};
    FILE *fp = fopen("data.bin", "wb"); // バイナリ書き込みモードで開きます。
    if (fp == NULL) {
        perror("fopen");
        return EXIT_FAILURE;
    }
    size_t written = fwrite(&rec, sizeof(Record), 1, fp);
    if (written != 1) {
        fprintf(stderr, "書き込みに失敗しました。\n");
    }
    fclose(fp);

    // バイナリファイルから構造体データを読み込みます。
    Record rec2 = {0};
    fp = fopen("data.bin", "rb"); // バイナリ読み込みモードで開きます。
    if (fp == NULL) {
        perror("fopen");
        return EXIT_FAILURE;
    }
    size_t read_count = fread(&rec2, sizeof(Record), 1, fp);
    fclose(fp);

    if (read_count == 1) {
        printf("id = %d\n", rec2.id);       // 『id = 42』と出力されます。
        printf("score = %.1f\n", rec2.score); // 『score = 98.5』と出力されます。
    }
    return 0;
}
gcc fread_fwrite.c -o fread_fwrite
./fread_fwrite
id = 42
score = 98.5
fread_fwrite2.c — 構造体の配列をまとめて読み書きする
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NAME 32

typedef struct {
    int   id;
    char  name[MAX_NAME];
    float power;
} Fighter;

int main(void) {
    Fighter fighters[] = {
        {1, "Son Goku",  9000.0f},
        {2, "Vegeta",    8000.0f},
        {3, "Piccolo",   3500.0f},
    };
    int count = (int)(sizeof(fighters) / sizeof(fighters[0]));

    // 配列を一括書き込みします。
    FILE *fp = fopen("fighters.bin", "wb");
    if (fp == NULL) { perror("fopen"); return EXIT_FAILURE; }
    fwrite(fighters, sizeof(Fighter), count, fp);
    fclose(fp);

    // 一括読み込みします。
    Fighter loaded[3];
    fp = fopen("fighters.bin", "rb");
    if (fp == NULL) { perror("fopen"); return EXIT_FAILURE; }
    size_t n = fread(loaded, sizeof(Fighter), count, fp);
    fclose(fp);

    for (size_t i = 0; i < n; i++) {
        printf("id=%d name=%-10s power=%.1f\n",
               loaded[i].id, loaded[i].name, loaded[i].power);
    }
    remove("fighters.bin");
    return 0;
}
gcc fread_fwrite2.c -o fread_fwrite2
./fread_fwrite2
id=1 name=Son Goku   power=9000.0
id=2 name=Vegeta     power=8000.0
id=3 name=Piccolo    power=3500.0
fread_fwrite3.c — バイナリファイルに追記して全件読み込む
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int   id;
    float score;
} Entry;

int main(void) {
    // 初回書き込み
    Entry e1 = {1, 85.5f};
    FILE *fp = fopen("scores.bin", "wb");
    if (fp == NULL) { perror("fopen"); return EXIT_FAILURE; }
    fwrite(&e1, sizeof(Entry), 1, fp);
    fclose(fp);

    // 追記モードでデータを追加します。
    Entry e2 = {2, 92.0f};
    Entry e3 = {3, 78.3f};
    fp = fopen("scores.bin", "ab"); // "ab" = バイナリ追記モード
    if (fp == NULL) { perror("fopen"); return EXIT_FAILURE; }
    fwrite(&e2, sizeof(Entry), 1, fp);
    fwrite(&e3, sizeof(Entry), 1, fp);
    fclose(fp);

    // 全件読み込みします。
    fp = fopen("scores.bin", "rb");
    if (fp == NULL) { perror("fopen"); return EXIT_FAILURE; }
    Entry buf;
    while (fread(&buf, sizeof(Entry), 1, fp) == 1) {
        printf("id=%d score=%.1f\n", buf.id, buf.score);
    }
    fclose(fp);
    remove("scores.bin");
    return 0;
}
gcc fread_fwrite3.c -o fread_fwrite3
./fread_fwrite3
id=1 score=85.5
id=2 score=92.0
id=3 score=78.3

概要

ファイルを開く際はバイナリモード(『"rb"』『"wb"』『"ab"』)を必ず指定してください。テキストモードで開くと Windows 環境で改行コード('\n' ↔ "\r\n")の自動変換が行われ、バイナリデータが壊れます。

『fread()』の戻り値が要求した count より少ない場合は、ファイル末尾(EOF)またはエラーのどちらかです。『feof() / ferror()』で原因を切り分けてください。

複数ブロックをまとめて読み書きするとシステムコールの回数が減り、処理が高速になります。ファイル位置の操作は『fseek()』で行えます。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。