🖥️

【C言語超入門】 第27回 バイナリファイル

2024/12/25に公開

https://youtu.be/ErRPp0dLMjM

四国めたん
\textcolor{pink}{四国めたん: }教師役ですわ

ずんだもん
\textcolor{lime}{ずんだもん: }生徒役なのだ

\footnotesize \textcolor{pink}{四国めたん:} 皆さん、こんにちは。四国めたんです

\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回もC言語のお勉強をしていきましょう

\footnotesize \textcolor{lime}{ずんだもん:} レッツゴーなのだ

\footnotesize \textcolor{pink}{四国めたん:} 前回は日本語を含めた文字列をファイルに出力したりファイルから入力したりする方法をお話ししましたわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルのオープンとクローズについての話もあったのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回は、文字列ではなく、データをファイルに出力したりファイルから入力したりする方法をお話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} よろしくお願いなのだ

ファイルのオープンとクローズ再び

\footnotesize \textcolor{pink}{四国めたん:} ファイルの読み書きを行うためには、まずファイルをオープンする必要がありますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルをオープンせずに、直接、読み書きすることはできないのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、バイナリファイル、つまり、データのファイルのオープンは、テキストファイルと同じくfopen関数によって行いますわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式はFILE* fopen(const char* filename, const char* mode)だったのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、filenameにオープンするファイルの名前をセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} テキストファイルと同じなのだ

\footnotesize \textcolor{pink}{四国めたん:} modeにはファイルをどのようにオープンするかを文字列としてセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} これもテキストファイルと同じなのか?

\footnotesize \textcolor{pink}{四国めたん:} いいえ、modeについては、セットする値が、テキストファイルとは異なりますわ

\footnotesize \textcolor{lime}{ずんだもん:} その辺りを詳しく教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} 後ほど説明するので、もう少し待ってくださいね

\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ

\footnotesize \textcolor{pink}{四国めたん:} 戻り値は、テキストファイルと同じく、 FILE型 のポインタですわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルのオープンに失敗するとNULLが返るのか...

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} バイナリファイルのクローズは、テキストファイルの場合と全く同じですわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式はint fclose(FILE* stream)だったのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、streamにはfopen関数で取得した FILE型 のポインタを指定しますわね

\footnotesize \textcolor{lime}{ずんだもん:} たしか、NULLは指定できなかったのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} なお、戻り値は、クローズが成功すれば0、失敗すればそれ以外の値が返りますわね

\footnotesize \textcolor{lime}{ずんだもん:} 一旦、ファイルをクローズすると、ファイルへの操作、例えば読み書きはできなくなるのだ

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{pink}{四国めたん:} それでは、Cドライブ直下に"temp"フォルダがあることを確認して、プログラムを実行してみましょう

Cドライブ直下のtempフォルダ

#include <stdio.h>

void main() {
  FILE* pf = fopen("C:\\temp\\テスト.bin", "wb");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました\n");
    fclose(pf);
  } else {
    printf("ファイルのオープンに失敗しました\n");
  }
}

fopen,fclose

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、"temp"フォルダの下に"テスト.bin"というファイルができましたわ

tempフォルダのテストファイル

\footnotesize \textcolor{lime}{ずんだもん:} fopenの引数について、もう少し詳しく教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

filenameにファイル名を指定します

\footnotesize \textcolor{pink}{四国めたん:} まず、filenameにオープンするファイルの名前をセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイル名に決まりはあるのか?

\footnotesize \textcolor{pink}{四国めたん:} 一部、使えない記号がありますが、ファイル名はかなり自由に決めることができますわ

\footnotesize \textcolor{lime}{ずんだもん:} そういえば、使えない記号があったのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、このような文字ですわ

  • 円記号(\small\yen)、もしくはバックスラッシュ(\small\backslash)
  • 斜線、スラッシュ(/)
  • コロン(:)
  • アスタリスク(*)
  • 疑問符、クエスチョンマーク(?)
  • ダブルコーテーション(")
  • 不等号(<>)
  • 縦線、パイプライン(|)

\footnotesize \textcolor{lime}{ずんだもん:} 結構、あるのだ

\footnotesize \textcolor{pink}{四国めたん:} それと、ファイル名には 拡張子 が付きますが、一般的なバイナリファイルの拡張子は".bin"を使いますわね

\footnotesize \textcolor{lime}{ずんだもん:} 他の拡張子は使えないのか?

\footnotesize \textcolor{pink}{四国めたん:} いえ、他の拡張子でも問題はありませんわ

\footnotesize \textcolor{pink}{四国めたん:} それから、ファイル名にはディレクトリも含めることができますわ

\footnotesize \textcolor{lime}{ずんだもん:} サンプルのプログラムでもディレクトリを含めていたのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{lime}{ずんだもん:} ところでディレクトリの区切りはバックスラッシュもしくは円マークが2重になっていたが...

\footnotesize \textcolor{pink}{四国めたん:} いい所に気が付きましたわね

\footnotesize \textcolor{pink}{四国めたん:} 通常は、ディレクトリの区切りはバックスラッシュ"\small\backslash"もしくは円マーク"\small\yen"ですわ

\footnotesize \textcolor{pink}{四国めたん:} ですが、文字列中では2つ重ねますわ

\footnotesize \textcolor{lime}{ずんだもん:} そういえば、エスケープシーケンスとして扱うのだったか?

\footnotesize \textcolor{pink}{四国めたん:} はい、文字列中のバックスラッシュ"\small\backslash"もしくは円マーク"\small\yen"はエスケープシーケンスの一部と見なされるのですわ

\footnotesize \textcolor{lime}{ずんだもん:} 改行文字"\small\backslashn"と同じ扱いだったのだ

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} つまり、エスケープシーケンスとして、バックスラッシュ"\small\backslash"もしくは円マーク"\small\yen"は二重にして"\small\backslash\small\backslash", "\small\yen\small\yen"と記述するのですわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに、アクセスの許可がないディレクトリ、例えばCドライブ直下などを指定するとオープンが失敗しますわ

\footnotesize \textcolor{lime}{ずんだもん:} だから"temp"フォルダの下のファイルを指定したのか...

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{lime}{ずんだもん:} ところで、ファイル名に日本語を使っているが、問題ないのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、問題ありませんわね

modeにオープンモードを設定します

\footnotesize \textcolor{pink}{四国めたん:} 次に、modeにはファイルのオープン方法を文字列で指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのような文字列を使うのだ?

\footnotesize \textcolor{pink}{四国めたん:} 色々とあるのですが、バイナリファイルで良く使うのは3つのモードですわ

モード

mode 意味
"wb" データの書き出し専用としてオープン
"rb" データの読み込み専用としてオープン
"ab" データの追加書き出し専用としてオープン

\footnotesize \textcolor{lime}{ずんだもん:} テキストファイルのモードに"b"が付いただけのように見えるのだが...

\footnotesize \textcolor{pink}{四国めたん:} その通りですわね

\footnotesize \textcolor{pink}{四国めたん:} まず、modeが"wb"の場合には、データの書き出し専用としてファイルをオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルが存在しない場合は新しく作成されるとして、既にファイルが存在する場合は、どうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} 指定のファイルが既に存在する場合には上書きされますわ

\footnotesize \textcolor{lime}{ずんだもん:} 気を付けるのだ

\footnotesize \textcolor{pink}{四国めたん:} 次にmodeが"rb"の場合には、データの読み込み専用としてファイルをオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 指定のファイルが存在しない場合には、どうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルのオープンが失敗して、戻り値がNULLとなりますわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} 最後にmodeが"ab"の場合にも、"wb"と同じくデータの書き出し専用としてファイルをオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} "wb"との違いはなんなのだ?

\footnotesize \textcolor{pink}{四国めたん:} "wb"では既存のファイルに上書きされてしまうのに対して、"ab"では既存のファイルの最後からデータを追加しますわ

\footnotesize \textcolor{lime}{ずんだもん:} ところでmodeが"ab"の場合に、指定のファイルが存在しない場合はどうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} "wb"と同様、指定のファイルが存在しなければ、新たに作成されますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

ファイルの同時読み書き

戻り値はFILE型のポインタです

\footnotesize \textcolor{pink}{四国めたん:} fopenFILE型 のポインタを戻しますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルを扱う際に使用する ハンドル だったのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、特別な構造体ですので大文字で表記されますわ

\footnotesize \textcolor{lime}{ずんだもん:} C標準ライブラリで定義された独自の型なのだ

\footnotesize \textcolor{pink}{四国めたん:} なお、構造体の内容についてはシステム毎に異なっているので、あまり気にする必要はありませんわ

\footnotesize \textcolor{lime}{ずんだもん:} とりあえずスルーしておくのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみにfopenで取得した FILE型 のポインタは、ファイルを操作する時には必ず指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 重要なのだ

ファイルにデータを書き出します

\footnotesize \textcolor{pink}{四国めたん:} fopenでモードを"wb"や"ab"にしてファイルをオープンすると、ファイルにデータを書き出すことができますわ

\footnotesize \textcolor{lime}{ずんだもん:} 最後にfcloseでファイルをクローズすることを忘れてはいけないのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、次にオープンしたファイルにデータを書き出してみようと思いますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのようにして書き出すのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルへのデータの書き出しは、幾つかの関数で可能ですわ

\footnotesize \textcolor{lime}{ずんだもん:} いくつもあるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、そのうちの簡単な関数fwriteについてお話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} おねがいするのだ

fwrite

\footnotesize \textcolor{lime}{ずんだもん:} fwriteは、どのような関数なのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルに指定のデータをそのまま書き出す関数ですわね

\footnotesize \textcolor{lime}{ずんだもん:} どんな形式なのだ?

\footnotesize \textcolor{pink}{四国めたん:} 形式としてはsize_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream )となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 詳しく説明してほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

\footnotesize \textcolor{pink}{四国めたん:} まず、ptrに書き出すデータへのポインタをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} void型 のポインタということは、どんな型のデータでもOKということか

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{pink}{四国めたん:} そして、sizeにデータの型のサイズをバイト単位で指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 書き出すデータが int型 の配列なら、 int型 のサイズを表すsizeof(int)を指定するということか?

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} そして、countには、書き出すデータの要素数を指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 書き出すデータが配列であれば、配列の要素数を指定するということか?

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} 結果的に(size×count)バイトのデータが書き出されますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} streamには、fopenで取得したファイルハンドルをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} この関数も、ファイルハンドルをセットする引数の位置が最後になっているのだ

\footnotesize \textcolor{pink}{四国めたん:} 戻り値は書き出した要素数ですわ

\footnotesize \textcolor{lime}{ずんだもん:} バイト数ではないのだな

\footnotesize \textcolor{pink}{四国めたん:} はい、書き出しが成功すればcountと同じ値、失敗すればcount未満の値となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 具体例をおねがいするのだ

#include <stdio.h>

typedef enum {
  RED,
  YELLOW,
  GREEN,
} fruit_color;

typedef struct {
  int weight;
  fruit_color color;
} fruit;

void main() {
  fruit apple[] = {
      {100, RED},
      {120, YELLOW},
      {90, GREEN},
  };

  FILE* pf = fopen("C:\\temp\\テスト.bin", "wb");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました。\n");

    size_t count = sizeof(apple) / sizeof(fruit);
    size_t write_len = fwrite(apple, sizeof(fruit), count, pf);
    if (write_len == count) {
      printf("データの書き出しに成功しました。\n");
    }

    fclose(pf);
    pf = NULL;
  } else {
    printf("ファイルのオープンに失敗しました。\n");
  }
}

fwriteの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました。」、「データの書き出しに成功しました。」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、今回のサンプルでは、構造体の配列をそのまま書き出してみましたわ

\footnotesize \textcolor{lime}{ずんだもん:} 書き出したファイルの中身を見ることはできるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、書き出したファイルの中身はVisual Studioの ファイル開くファイル... からオープンすれば見ることができますわ

fwriteのファイルの中身

\footnotesize \textcolor{lime}{ずんだもん:} なんか、数字が並んでいるだけで、よく分からないのだ

\footnotesize \textcolor{pink}{四国めたん:} まぁ、そうですわね

\footnotesize \textcolor{lime}{ずんだもん:} ところで、プログラム内でsize_t count = sizeof(apple) / sizeof(fruit);としている部分について教えて欲しいのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、この部分は配列の要素数を取得している部分ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 要素数は3ではないのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、配列のサイズが分からない場合に、計算で求めるための例として、今回は使いましたわ

\footnotesize \textcolor{lime}{ずんだもん:} チョットしたテクニックなのだ

ファイルからデータを読み込みます

\footnotesize \textcolor{pink}{四国めたん:} fopenでモードを"rb"にしてファイルをオープンすると、ファイルからデータを読み込むことができますわ

\footnotesize \textcolor{lime}{ずんだもん:} 最後にfcloseでファイルをクローズすることを忘れてはいけないのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、次にオープンしたファイルからデータを読み込んでみようと思いますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのようにして読み込むのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルからのデータの読み込みは、幾つかの関数で可能ですわ

\footnotesize \textcolor{lime}{ずんだもん:} いくつもあるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、そのうちの簡単な関数freadについてお話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} おねがいするのだ

fread

\footnotesize \textcolor{lime}{ずんだもん:} freadは、どのような関数なのだ?

\footnotesize \textcolor{pink}{四国めたん:} ファイルからデータをそのまま読み込む関数ですわね

\footnotesize \textcolor{lime}{ずんだもん:} どんな形式なのだ?

\footnotesize \textcolor{pink}{四国めたん:} 形式としてはsize_t fread(void* ptr, size_t size, size_t count, FILE* stream)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 詳しく説明してほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

\footnotesize \textcolor{pink}{四国めたん:} まず、ptrにデータを読み込むメモリ領域へのポインタをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} void型 のポインタということは、どんな型のメモリ領域でもOKということか

\footnotesize \textcolor{pink}{四国めたん:} そうですわね

\footnotesize \textcolor{pink}{四国めたん:} そして、sizeにデータの型のサイズをバイト単位で指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 読み込むデータが int型 なら、 int型 のサイズを表すsizeof(int)を指定するということか?

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} そして、countには、読み込むデータの要素数を指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} ptrに指定したメモリ領域が配列であれば、配列の要素数等を指定するということか?

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} 結果的に(size×count)バイトのデータが読み込まれますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに、ptrに指定したメモリ領域のサイズを超えるサイズを指定してはいけませんわ

\footnotesize \textcolor{lime}{ずんだもん:} サイズが大きすぎるとどうなるのだ

\footnotesize \textcolor{pink}{四国めたん:} 他のデータを破壊する可能性がありますわね

\footnotesize \textcolor{lime}{ずんだもん:} それは大変なのだ

\footnotesize \textcolor{pink}{四国めたん:} そして、streamには、fopenで取得したファイルハンドルをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} この関数も、ファイルハンドルをセットする引数の位置が最後になっているのだ

\footnotesize \textcolor{pink}{四国めたん:} 戻り値は読み込んだ要素数ですわ

\footnotesize \textcolor{lime}{ずんだもん:} バイト数ではないのだな

\footnotesize \textcolor{pink}{四国めたん:} はい、読み込みが成功すればcountと同じ値、失敗すればcount未満の値となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 具体例をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

\footnotesize \textcolor{pink}{四国めたん:} なお、実行する際にはfwriteで出力した"テスト.bin"ファイルが存在することが前提ですわ

#include <stdio.h>

#define SIZE (3)

typedef enum {
  RED,
  YELLOW,
  GREEN,
} fruit_color;

typedef struct {
  int weight;
  fruit_color color;
} fruit;

void main() {
  fruit apple[SIZE] = {0};

  FILE* pf = fopen("C:\\temp\\テスト.bin", "rb");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました。\n");

    size_t read_len = fread(apple, sizeof(fruit), SIZE, pf);
    if (read_len == SIZE) {
      for (size_t i = 0; i < SIZE; i++) {
        printf("リンゴの重さは%dグラムです。\n", apple[i].weight);
        if (apple[i].color == RED) {
          printf("リンゴの色は赤色です。\n");
        } else if (apple[i].color == YELLOW) {
          printf("リンゴの色は黄色です。\n");
        } else {
          printf("リンゴの色は緑色です。\n");
        }
      }
    }

    fclose(pf);
    pf = NULL;
  } else {
    printf("ファイルのオープンに失敗しました。\n");
  }
}

freadの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました。」

\footnotesize \textcolor{lime}{ずんだもん:} 「リンゴの重さは100グラムです。」

\footnotesize \textcolor{lime}{ずんだもん:} 「リンゴの色は赤色です。」

\footnotesize \textcolor{lime}{ずんだもん:} 「リンゴの重さは120グラムです。」

\footnotesize \textcolor{lime}{ずんだもん:} 「リンゴの色は黄色です。」

\footnotesize \textcolor{lime}{ずんだもん:} 「リンゴの重さは90グラムです。」

\footnotesize \textcolor{lime}{ずんだもん:} 「リンゴの色は緑色です。」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、fwriteのサンプルプログラムのappleの配列の初期化の値と同じになっていますわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} 基本的に、構造体や列挙体がfwriteで書き出したときと同じであれば、同じデータを読み込むことができますわね

読み込み / 書き出し位置を取得 / 移動します

\footnotesize \textcolor{pink}{四国めたん:} 今までは、文字列やデータの読み込み、書き出しは、ファイルの先頭から順番に行われていましたわ

\footnotesize \textcolor{lime}{ずんだもん:} 最後に追加というのもあったのだ

\footnotesize \textcolor{pink}{四国めたん:} ただ、文字列やデータの読み込みなどは、ファイルの途中から行いたい場合も多くありますわね

\footnotesize \textcolor{lime}{ずんだもん:} たしかに

\footnotesize \textcolor{pink}{四国めたん:} ですので、現在、ファイルのどの位置を読み込んでいるのかを取得する関数が提供されていますわ

\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、また、ファイルの読み込み位置を移動する関数も提供されていますわ

\footnotesize \textcolor{lime}{ずんだもん:} うむ、いろいろとべんりそうなのだ

\footnotesize \textcolor{pink}{四国めたん:} なお、ファイルの読み込み位置や書き込み位置のことを ファイルポインタ と言いますわ

ftell

\footnotesize \textcolor{pink}{四国めたん:} まずはftellですわ

\footnotesize \textcolor{lime}{ずんだもん:} ftell

\footnotesize \textcolor{pink}{四国めたん:} はい、現在のファイルの読み込み位置や書き出し位置を取得する関数ですわ

\footnotesize \textcolor{lime}{ずんだもん:} どのような形式なのだ?

\footnotesize \textcolor{pink}{四国めたん:} 形式としてはlong ftell(FILE* stream)ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 詳しく教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、streamにはfopenで取得したファイルハンドルをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} そして、戻り値はファイルポインタの位置ですわ

\footnotesize \textcolor{lime}{ずんだもん:} longは何なのだ

\footnotesize \textcolor{pink}{四国めたん:} long型int型 と同じく整数を表す型で、一般的に-2,147,483,648 ~ 2,147,483,647の範囲を表せますわ

\footnotesize \textcolor{lime}{ずんだもん:} お~、すごく大きな数を表せるのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに、バイナリファイルでは、戻り値はバイト単位ですわ

\footnotesize \textcolor{lime}{ずんだもん:} テキストファイルでは違うのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、テキストファイルではバイト単位ではありませんし、文字数でもありませんので注意が必要ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 気を付けるのだ

fseek

\footnotesize \textcolor{pink}{四国めたん:} 次はfseekですわ

\footnotesize \textcolor{lime}{ずんだもん:} fseek

\footnotesize \textcolor{pink}{四国めたん:} はい、現在のファイルの読み込み位置や書き出し位置を移動しますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのような形式なのだ?

\footnotesize \textcolor{pink}{四国めたん:} 形式としてはint fseek(FILE* stream, long offset, int origin)ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 詳しく教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} まず、streamにはfopenで取得したファイルハンドルをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} 次に、offsetは移動する位置をバイト単位で指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルの先頭からの位置ということか?

\footnotesize \textcolor{pink}{四国めたん:} いいえ、offsetでの移動の基点はoriginで指定しますわ

\footnotesize \textcolor{lime}{ずんだもん:} どのように指定するのだ?

\footnotesize \textcolor{pink}{四国めたん:} 指定できる値は列挙体で3つ、決められていますわ

  • SEEK_SET: ファイルの先頭
  • SEEK_CUR: 現在の位置
  • SEEKEND: ファイルの最後

\footnotesize \textcolor{lime}{ずんだもん:} 3つ以外の値を指定した場合はどうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} 分かりませんわ

\footnotesize \textcolor{lime}{ずんだもん:} はぁ?

\footnotesize \textcolor{pink}{四国めたん:} どのようになるかは、決まっていませんので、3つ以外は指定しないでくださいね

\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ

\footnotesize \textcolor{pink}{四国めたん:} 戻り値については、移動が成功した場合には0が返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} 移動が失敗した場合には0以外が返るということか

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

ファイルのサイズを取得します

\footnotesize \textcolor{pink}{四国めたん:} 実は、C標準ライブラリには、ファイルサイズを直接取得する関数はありませんわ

\footnotesize \textcolor{lime}{ずんだもん:} え~、残念なのだ

\footnotesize \textcolor{pink}{四国めたん:} ですので、ftellfseekを使って、バイナリファイルのサイズを取得するテクニックを紹介しますわ

\footnotesize \textcolor{lime}{ずんだもん:} バイナリファイルのみなのか?

\footnotesize \textcolor{pink}{四国めたん:} テキストファイルでも、バイナリファイルとして扱うことで、同じことができますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

#include <stdio.h>

void main() {
  FILE* pf = fopen("C:\\temp\\テスト.bin", "rb");

  if (pf != NULL) {
    printf("ファイルのオープンに成功しました。\n");

    if (!fseek(pf, 0, SEEK_END)) {
      long pos = ftell(pf);
      printf("ファイルサイズは%ldです。\n", pos);
    }

    fclose(pf);
  } else {
    printf("ファイルのオープンに失敗しました。\n");
  }
}

ファイルサイズ

\footnotesize \textcolor{lime}{ずんだもん:} 「ファイルのオープンに成功しました」、「ファイルサイズは24です。」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、実際のファイルのプロパティーは、24バイトとなっているはずですわ

プロパティ

\footnotesize \textcolor{lime}{ずんだもん:} ところで、プログラムの説明をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} まず、ファイルをバイナリファイルとしてオープンしますわ

\footnotesize \textcolor{lime}{ずんだもん:} fopenを"rb"モードで呼び出しているのだ

\footnotesize \textcolor{pink}{四国めたん:} 次に、originSEEK_ENDに、offsetを0にしてファイルポインタをファイルの最後に移動させますわ

\footnotesize \textcolor{lime}{ずんだもん:} 移動が成功すれば、0、つまり、falseが返るので、否定演算子"!"でtrueにして、if文内を実行しているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、if文内では、ftellでファイルの最後の位置をバイト単位で取得しますわ

\footnotesize \textcolor{lime}{ずんだもん:} ファイルの最後の位置、つまり、ファイルサイズをバイト単位で取得できるということか

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

2G以上のサイズのファイル

最近では、2Gバイト以上のサイズのファイルが珍しく無くなってきました

ビデオのファイル等は、2Gどころか4G以上のファイルも出てきています

スクリーンサイズも増加していることもあり、ファイルサイズは今後も増え続けると思います

ただ、ftellfseekは、戻り値やoffsetlong型 となっているため、サイズが2G以上のファイルを扱うことが難しいい状況です

そのためC99からftellofseekoという関数が追加されました

ただ、実装されていないシステムも多く、実装されていても扱えるファイルサイズはシステム依存となっているようで、不安定です

ですので、現状、各システムで独自の関数を用意しています

Visual Studioでは、_ftelli64_fseeki64という関数を使うことができます

その他ftello64fseeko64などの関数が用意されているシステムもあります

扱えるファイルのサイズはエクサバイト以上となりますので、当面は困らない範囲です

まとめ

\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした

\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ

\footnotesize \textcolor{pink}{四国めたん:} 以上で バイナリファイル についての説明は終わりですわ

Discussion