バイナリデータとしてファイルに保存されたデータをfread関数を使って配列に読み込んだ後コマンドプロンプト画面に表示してみます 

アレサ「


さきほどのプログラム


#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","wb");

if(fp==NULL){

printf("ファイルオープンに失敗しましたよ~ん\n");

return -1;}

else printf("Hallo!ファイルオープンに成功しましたよ~ん\n");


int hairetu[]={1,2,3};

fwrite(&hairetu[0],sizeof(int),1,fp);

fwrite(&hairetu[1],sizeof(int),1,fp);

fwrite(&hairetu[2],sizeof(int),1,fp);


fclose(fp);

return 0;

}

では

数値

1

2

3

バイナリデータ


として


TEN-GOGO-C-language.binファイルに保存してきました


今度は


このバイナリファイルから

バイナリデータとなった

1

2

3

をよみこんで


コマンドプロンプト画面に表示してみたいと思います


そのプログラムは


#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");

if(fp==NULL){

printf("ファイルオープンに失敗しましたよ~ん\n");

return -1;}

else printf("Hello!ファイルオープンに成功しましたよ~ん\n");


int hairetu[3];

fread(&hairetu[0],sizeof(int),1,fp);

fread(&hairetu[1],sizeof(int),1,fp);

fread(&hairetu[2],sizeof(int),1,fp);


printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[1]);

printf("%d\n",hairetu[2]);


fclose(fp);

return 0;

}


コンパイル結果


Hello!ファイルオープンに成功しましたよ~ん

1

2

3


となります。


コマンドプロンプト画面に


数値

1

2

3

を表示するには


このプログラムのように


ファイルポインタ変数宣言とfopen関数の設定


で 


バイナリファイルからのデータ読み取り機能を持つ


オープンモード”rb”を設定し


バイナリファイルを開きます。


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");


そして


バイナリファイルとしてハードディスクのファイルに保存されたデータをコンピュータのメモリに読み込むためには


テキストファイルとしてハードディスクのファイルに保存されたデータを

コンピュータのメモリに読み込む


fscanf関数でなく


バイナリファイルデータ読み込み専用の関数である


fread関数をもちいます。


(freadはfile readの略です)


もう1度


さきほどのプログラムを表示してみます


#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");

if(fp==NULL){

printf("ファイルオープンに失敗しましたよ~ん\n");

return -1;}

else printf("Hello!ファイルオープンに成功しましたよ~ん\n");

int hairetu[3];

fread(&hairetu[0],sizeof(int),1,fp);

fread(&hairetu[1],sizeof(int),1,fp);

fread(&hairetu[2],sizeof(int),1,fp);


printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[1]);

printf("%d\n",hairetu[2]);


fclose(fp);

return 0;

}


コンパイル結果


Hello!ファイルオープンに成功しましたよ~ん

1

2

3


このプログラムはバイナリファイルからデータを


配列に格納


配列に格納されたデータを


printf表示するものなので


まず初めに


バイナリファイルに読み込むためのデータが保存されている必要があります


ここでは

先程のプログラム


#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","wb");

if(fp==NULL){

printf("ファイルオープンに失敗しましたよ~ん\n");

return -1;}

else printf("Hello!ファイルオープンに成功しましたよ~ん\n");

int hairetu[]={1,2,3};

fwrite(&hairetu[0],sizeof(int),1,fp);

fwrite(&hairetu[1],sizeof(int),1,fp);

fwrite(&hairetu[2],sizeof(int),1,fp);


fclose(fp);

return 0;

}

をもちいて


数値

1

2

3

バイナリデータ


として


TEN-GOGO-C-language.binファイルに保存されているとします。



fscanf関数のエピソードのときと同じように


まずコンピュータのメモリに


バイナリファイルから読み取ったデータを格納するために


配列宣言int hairetu[3];


をおこないます


そうして


配列宣言int hairetu[3];


によってつくられる

配列変数

hairetu[0]

hairetu[1]

hairetu[2]


fread関数をつかって


バイナリファイルにバイナリデータとして保存されている


数値

1

2

3

をとりこんでいきます。


fread関数は次のように記述して用いられます。


fread(&hairetu[0],sizeof(int),1,fp);


ここでfread関数の


1番目の引数には


データを格納したいメモリのアドレス


この場合は&hairetu[0]がかきこまれています。


2番目の引数には


バイナリファイルからデータを何バイト単位で配列に読み込むかを


かきこみます。


fread(&hairetu[0],sizeof(int),1,fp);

fread(&hairetu[0],4,1,fp);

相当します。


sizeof(int)はint型の格納容量である

4を表しているのですね。


なぜ

sizeof(int)が

用いられるのかというと


整数値データである

1

2

3

int型の配列変数

hairetu[0]

hairetu[1]

hairetu[2]

格納するので

int型の4バイト単位で

int型の配列変数

hairetu[0]

hairetu[1]

hairetu[2]

に格納すればいいというわけで

sizeof(int)と記述されています。


それに

もともと

1

2

3


int型の配列変数

hairetu[0]

hairetu[1]

hairetu[2]

に格納されていたものが

fwrite関数により

バイナリファイルに書き込まれたので


00000000000000000000000000000001

00000000000000000000000000000010

00000000000000000000000000000011

で表されるように

4バイトのデータ量をもっています。



バイナリファイルから


整数の数値データをint型の配列hairetuに格納する

つまり

データを4バイト単位で配列hairetuに格納する場合は


fread関数の第2引数に


fread(&hairetu[0],4,1,fp);


のように4を


バイナリファイルから


実数の数値データをdouble型の配列hairetuに格納する

つまり

データを8バイト単位で配列hairetuに格納する場合は


fread関数の第2引数に


fread(&hairetu[0],8,1,fp);

のように

8

をかきこみます


バイナリファイルから


整数の数値データを配列に格納する場合は


fread関数の第2引数に sizeof(int)


バイナリファイルから


実数の数値データを配列に格納する場合は


fread関数の第2引数に sizeof(float)


かきこむ場合があるのですね


sizeof(int)は4バイト

sizeof(float)は8バイトをあらわしていますね


ですから


fread(&hairetu[0],4,1,fp);

fread(&hairetu[1],4,1,fp);

fread(&hairetu[2],4,1,fp);


または

fread(&hairetu[0],sizeof(int),1,fp);

fread(&hairetu[1],sizeof(int),1,fp);

fread(&hairetu[2],sizeof(int),1,fp);


と記述されたなら


配列宣言

int hairetu[3];


によって作製された

int型の4バイトの容量をもつ

配列変数

hairetu[0](4バイト)

hairetu[1](4バイト)

hairetu[2](4バイト)


sizeof(int)、4バイト単位で


ファイルポインタ変数fpの格納しているアドレスのメモリに集められた


バイナリファイル内のバイナリデータを格納することになります。


3番目の引数1は読み取り回数をあらわしています。

fread(&hairetu[0],sizeof(int),1,fp);

fread(&hairetu[1],sizeof(int),1,fp);

fread(&hairetu[2],sizeof(int),1,fp);


この場合

hairetu[0]

hairetu[1]

hairetu[2]

数値データを読み取る回数は1回となっています」


ソーラー「読み取り回数?


ハードディスクのテキストファイルからデータを


読み込むときは


こんな項目はなかったよね?


これはいったいなんのことなのかな?アレサ」


アレサ「それでは


読み取り回数を0回に設定した


fread(&hairetu[0],sizeof(int),0,fp);

fread(&hairetu[1],sizeof(int),0,fp);

fread(&hairetu[2],sizeof(int),0,fp);

をもちいた


次のプログラムを実行してみましょう


#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");

if(fp==NULL){

printf("ファイルオープンに失敗しましたよ~ん\n");

return -1;}

else printf("Hallo!ファイルオープンに成功しましたよ~ん\n");


int hairetu[3];


fread(&hairetu[0],sizeof(int),0,fp);

fread(&hairetu[1],sizeof(int),0,fp);

fread(&hairetu[2],sizeof(int),0,fp);

/*第3引数の読み込み回数が0回に設定されています*/

printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[1]);

printf("%d\n",hairetu[2]);


fclose(fp);

return 0;

}

コンパイル結果

1703760

1953650512

]1703808


ソーラー「面白いね 😊 これは 一体どうなってるの?


?????(*´▽`*)


どうもこの数値は


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

にデータが何も与えられず


初期化されないときに


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

に格納されている数値データみたいだけど・・・」



アレサ「😊そうなんですの


実は


fread(&hairetu[0],sizeof(int),0,fp);

fread(&hairetu[1],sizeof(int),0,fp);

fread(&hairetu[2],sizeof(int),0,fp);


のように

読み取り回数を0回に設定したため


配列int hairetu[3]内の

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

に数値は1回も書き込まれず


初期化されなかったのですの。


ですから


配列が初期化されなかった時に


hairetu[0]

hairetu[1]

hairetu[2]

に格納されている数値


1703760

1953650512

1703808

printf出力表示されたというわけなんですの。


これでは まだわかりにくいかもしれません。


それでは


fwrite(&hairetu[0],sizeof(int),0,fp);

fwrite(&hairetu[1],sizeof(int),1,fp);

fwrite(&hairetu[2],sizeof(int),0,fp);


のように

hairetu[0]への読み取り回数を0回に

hairetu[1]への読み取り回数を1回に

hairetu[2]への読み取り回数を0回に


設定した


次のプログラムを実行したならコンパイル結果はどうなるでしょうか?


#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");

if(fp==NULL){

printf("ファイルオープンに失敗しましたよ~ん\n");

return -1;}

else printf("Hallo!ファイルオープンに成功しましたよ~ん\n");


int hairetu[3];

fread(&hairetu[0],sizeof(int),0,fp);

fread(&hairetu[1],sizeof(int),1,fp);

fread(&hairetu[2],sizeof(int),0,fp);


printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[1]);

printf("%d\n",hairetu[2]);


fclose(fp);

return 0;

}


コンパイル結果

1703760

1

1703808


ソーラー「

hairetu[0]への読み取り回数を0回に

hairetu[2]への読み取り回数を0回に

設定したため

hairetu[0]

hairetu[2]

には

バイナリファイルから

何もデータが読み取られず

初期化されなかったため

先程の時と同じく

hairetu[0]

hairetu[2]

初期化されなかった時に格納されている数値


1703760

1703808

printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[2]);

により

コマンドプロンプト画面に

printf出力表示されたんだね。



そして

hairetu[1]への読み取り回数を1回に指定してあるので


hairetu[1]へは数値1が格納されたわけだけど

これは

hairetu[0]に格納されるはずだった数値1が

hairetu[0]に格納されなかったため

繰り下げて

hairetu[1]に数値1が格納されたというわけなんだね。」


アレサ「今の場合


バイナリファイル内のデータ


1

2

3


上から順に

fread関数の設定に従い


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

に読み込まれていくのですが


hairetu[0]に数値1が読み込まれなかったからと言って


数値1は読み込まれないまま飛ばされて


hairetu[1]に次の数値2が読み込まれるわけではなく


hairetu[1]にずれ込んでも

読み込まれなかった

数値1から

hairetu[1]に読み込まれていくのですね。



その例をもう1つみていきましょう。


fwrite(&hairetu[0],sizeof(int),0,fp);

fwrite(&hairetu[1],sizeof(int),0,fp);

fwrite(&hairetu[2],sizeof(int),1,fp);


のように

hairetu[0]への読み取り回数を0回に

hairetu[1]への読み取り回数を0回に

hairetu[2]への読み取り回数を1回に


設定した


次のプログラムを実行したならコンパイル結果は


どうなるでしょうか? ソーラーさん😊」


#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");

if(fp==NULL){

printf("ファイルオープンに失敗しましたよ~ん\n");

return -1;}

else printf("Hallo!ファイルオープンに成功しましたよ~ん\n");


int hairetu[3];

fread(&hairetu[0],sizeof(int),0,fp);

fread(&hairetu[1],sizeof(int),0,fp);

fread(&hairetu[2],sizeof(int),1,fp);


printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[1]);

printf("%d\n",hairetu[2]);


fclose(fp);

return 0;

}



ソーラー「よ~し、😊いいね、それではコンパイルっ。」


コンパイル結果


1703760

1953650512

1


ソーラー「

配列

hairetu[0]への読み取り回数を0回に

hairetu[1]への読み取り回数を0回に

hairetu[2]への読み取り回数を1回に

設定したので


hairetu[0]

hairetu[1]

には


何もデータが格納されず初期化されなかったんだね。


だから

hairetu[0]

hairetu[1]


が初期化されなかった時に


hairetu[0]

hairetu[1]


格納されている数値データ

1703760

1953650512

printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[1]);

により

コマンドプロンプト画面に

printf出力表示

されたんだね


そして

hairetu[0]

hairetu[1]

バイナリファイルのデータが格納されなかったので


hairetu[2]から


バイナリファイル内のデータ


1

2

3

の読み込みがはじまり

hairetu[2]に数値1が格納されたというわけなんだね。」



アレサ「そうなんですの


そして

4番目の引数には


ファイルポインタ変数宣言


FILE *fp;


によって作製された


ファイルポインタ変数fpが記述されています。


バイナリファイルTEN-GOGO-C-language.binが


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");

により


開かれて


fread(&hairetu[0],sizeof(int),1,fp);

fread(&hairetu[1],sizeof(int),1,fp);

fread(&hairetu[2],sizeof(int),1,fp);


が実行されると


ハードディスクのバイナリファイルからバイナリデータ



ファイルポインタ変数fpの格納しているアドレスのメモリに読み込まれていきます。


バイナリデータとなっている

1

2

3


まず

バイナリデータとなっている

1


fread(&hairetu[0],sizeof(int),1,fp);


が実行されることにより


ファイルポインタ変数fpが格納しているアドレスのメモリに格納されます。


(ファイルポインタ変数名をfpのまま変えることなく


同じメモリに次々とデータを上書きして格納することができるのが


ファイルポインタ変数の特徴でしたね)



そのファイルポインタ変数fpに格納されたアドレスのメモリに


fread関数はアクセスして


メモリに格納されている


バイナリデータ

1


配列変数hairetu[0]に格納します。


そのため


fread(&hairetu[0],sizeof(int),1,fp);


の第一引数には


配列変数hairetu[0]のアドレス


&hairetu[0]が記述されています。


次に


fread(&hairetu[1],sizeof(int),1,fp);


が実行されると


バイナリデータとなっている

2


バイナリデータとなっている

1


に上書きされて


ファイルポインタ変数fpの格納しているアドレスのメモリに格納されます。



(ファイルポインタ変数名をfpのまま変えることなく


同じメモリに次々とデータを上書きして格納することができるのが


ファイルポインタ変数の特徴でしたね)


そのファイルポインタ変数fpに格納されたアドレスのメモリに


fread関数はアクセスして


メモリに格納されている

バイナリデータ

2



配列変数hairetu[1]に格納します


そのため


fread(&hairetu[1],sizeof(int),1,fp);


の第一引数には


hairetu[1]のアドレス


&hairetu[1]が記述されています。



次に


fread(&hairetu[2],sizeof(int),1,fp);


が実行されると


バイナリデータとなっている

3


バイナリデータとなっている

2


に上書きされて


ファイルポインタ変数fpの格納しているアドレスのメモリに格納されます。



(ファイルポインタ変数名をfpのまま変えることなく


同じメモリに次々とデータを上書きして格納することができるのが


ファイルポインタ変数の特徴でしたね)


そのファイルポインタ変数fpに格納されたアドレスのメモリに


fread関数はアクセスして


メモリに格納されている

バイナリデータ

3



配列変数hairetu[2]に格納します


そのため


fread(&hairetu[2],sizeof(int),1,fp);


の第一引数には


hairetu[1]のアドレス


&hairetu[2]が記述されています。



fread関数はこのような仕組みとなっています」



ソーラー「バイナリファイルからデータ読み込んで


コマンドプロンプト画面に表示するまでの


大体の流れは


FILE *fp;

fp=fopen("TEN-GOGO-C-language.bin","rb");

により

ハードデイスク内のバイナリファイルを


読み取りできるよう開いた後


fread(&hairetu[0],sizeof(int),1,fp);

fread(&hairetu[1],sizeof(int),1,fp);

fread(&hairetu[2],sizeof(int),1,fp);


を実行して


バイナリファイルに保存されている

バイナリデータとなっている

1

2

3



用意した配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[0]=1

hairetu[1]=2

hairetu[2]=3

と取り込んで


printf("%d\n",hairetu[0]);

printf("%d\n",hairetu[1]);

printf("%d\n",hairetu[2]);


を実行し


コマンドプロンプト画面に


1

2

3

printf出力表示するという流れなんだね。」


アレサ「はいっそうなんです。」


ソーラー「ここで


バイナリファイルから


バイナリデータを配列に読み込んで


配列の中身を


コマンドプロンプト画面に


表示する際、


バイナリファイルに収められている


コンピュータが直接扱うことのできるバイナリデータ


00000000000000000000000000000001

00000000000000000000000000000010

00000000000000000000000000000011



人間でも読める普通のデータ


1

2

3


にもどされて表示されてるんだね。


というか


それは今までのすべてのプログラムで行われてきたことで(笑)


メモリに格納されたデータはすべてバイナリデータ


なんだよ😊


そのバイナリデータ


00000000000000000000000000000001

00000000000000000000000000000010

00000000000000000000000000000011


1

2

3

テキストファイルを開くソフトを使って


表示できるようハードディスクのファイルに


テキストファイルのフォーマット(データ保存形式)で保存するか


それとも


バイナリファイルのフォーマット(データ保存形式)で保存するか


2つの方法があるというわけなんだね。



それにしても


○○○○○○○○.binと表示されているファイルを


ときどき


PC内で見かけていたんだけど


バイナリファイルのことだったんだね



これで


数値データ


1

2

3



🐥ファイル名の末尾が.txtで表される


ふつうのテキストファイル



🐤ファイル名の末尾が.binで表される


コンピュータが直接扱っているデータ


のバイナリファイル


2つの形式でファイルに保存することができるように


なったね。


これって


もしかして


動画をMP4やWMV形式に 


いろいろ変換して保存するのも


原理的におんなじじゃない?


つまり1つの動画データを


何かの異なる

ファイルポインタ変数宣言とfopen関数の設定

を行い

fprintf関数やfwrite関数に当たるものを用いて


MP4やWMV形式に変換してファイルに保存してるんじゃない?」


アレサ

「そういえば、そうかもしれません


そしてファイルを開いてデータを読み込むときには


そのファイルを開くソフトにあたるものが必要です。


そのソフトにあたるものが


テキストファイル.txtなら


fscanf関数を用いたプログラムで


バイナリファイル.binなら


fread関数を用いたプログラムといえるのではないですか?」







  • Twitterで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る