バイナリデータとしてファイルに保存されたデータを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関数を用いたプログラムといえるのではないですか?」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます