データをコンピュータが直接扱えるバイナリデータに変換しファイルに保存してみよう そのファイルはバイナリファイルと呼ばれます
今までは
自分で打ち込んだ文章や数値データ等を、
ハードデイスク内のファイルに保存してきました
実はそれらのデータはテキストファイルで開くことができるよう
つまり ファイルを開いたとき文字や数値として認識できるよう
テキストファイルのフォーマット(データ保存形式)で保存されています。
そのようなファイルはテキストファイルと呼ばれます
テキストファイルであることがわかるように
その際
ファイル名の末尾に.txtをつけて
TEN-GOGO-C-language.txt
と
保存してきました。
そして
データをハードデイスク内のファイルに保存するための
ファイルポインタ変数宣言とfopen関数の設定は
FILE *fp;
fp=fopen("TEN-GOGO-C-language.txt","w");
でした
もちろん
テキストファイル形式でファイルが開かれると
文字や数値と認識されることができるといっても
データがハードディスクに格納されているときは
0と1で表されたデータとして保存されています。
自分で打ち込んだ文章や数値データ等を
テキストファイルのフォーマット(データ保存形式)でなく
バイナリファイルのフォーマット(データ保存形式)
で
ハードデイスク内のファイルに保存することができます
バイナリファイルのフォーマット(データ保存形式)で
ハードディスクにデータが保存されるときも
0と1で表されたデータとして保存されています。
バイナリファイルのフォーマット(データ保存形式)で保存されたデータは
バイナリデータと呼ばれます
バイナリデータが保存されているファイルは
バイナリファイルと呼ばれます
バイナリファイルであることがわかりやすいように
ファイル名は
末尾に
TEN-GOGO-C-language.binのように
.binをつけます
データがテキストファイルのフォーマット(データ保存形式)
でなく
バイナリファイルのフォーマット(データ保存形式)
で保存されると
様々な利点があります。
それをこれから確認していきましょう。
バイナリファイルとしてデータを保存する際は
ファイルポインタ変数宣言とfopen関数の設定は
FILE *fp;
fp=fopen("TEN-GOGO-C-language.txt","w");
でなく
FILE *fp;
fp=fopen("TEN-GOGO-C-language.bin","wb");
となります。
2つの
ファイルポインタ変数宣言とfopen関数の設定を
よく見比べてみると
fp=fopen("TEN-GOGO-C-language.txt","w");
と
fp=fopen("TEN-GOGO-C-language.bin","wb");
では
ファイル名が.txtから.binに
オープンモードが"w"から"wb"に変化しています。
ここでの
オープンモード"wb"は
オープンモード"w"に相当し
ハードディスク内に
TEN-GOGO-C-language.binファイルを作製し
新規書き込みできるモードで
TEN-GOGO-C-language.binファイルを開きます。
同様に
オープンモード "a","r" に相当する
オープンモード "ab","rb"もあり
それぞれ
追加書き込みモード
読み込み専用モード
となっています。
ここでファイル名を.binとしなくても
.yahoo や.comとしても
バイナリファイルを作成することはできますが
あとでそのファイルが
テキストファイルかバイナリファイルか
どのようなタイプのファイルだったか
判断できなくなるので
ファイル名を.binとしています。
バイナリファイルである
TEN-GOGO-C-language.binファイルを
新規作製、オープンしてからクローズするまでの
プログラムは次のようになります。
#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");
fclose(fp);
return 0;
}
コンパイル結果
Hello!ファイルオープンに成功しましたよ~ん
ファイルポインタ変数fp宣言、fopen関数の設定
FILE *fp;
fp=fopen("TEN-GOGO-C-language.bin","wb");
が行われると
ハードディスク内にバイナリファイルである
TEN-GOGO-C-language.binファイルがない場合は
新たに
TEN-GOGO-C-language.binファイルが作成され
オープンモード"wb"で開かれます。
ハードディスク内にバイナリファイルである
TEN-GOGO-C-language.binファイルがある場合は
そのハードディスク内のTEN-GOGO-C-language.binファイルが
オープンモード"wb"で開かれます。
そのとき
TEN-GOGO-C-language.binファイルに保存されていたデータは
消去されてしまいます。
このバイナリファイルを開くプログラムでも
ファイルオープンに成功していると
fopen("TEN-GOGO-C-language.bin","wb")は
NULL以外の戻り値を
ファイルオープンに失敗していると
fopen("TEN-GOGO-C-language.bin","wb")は
NULLという戻り値を持つよう
設定されています
ファイルオープンに失敗していると
fp=fopen("TEN-GOGO-C-language.bin","wb");
より
ファイルポインタ変数fpは
fp=NULLという値を持つようになるので
バイナリファイルが正常にオープンしているかどうかを確認するために
if(fp==NULL){
printf("ファイルオープンに失敗しましたよ~ん\n");
return -1;}
else printf("Hello!ファイルオープンに成功しましたよ~ん\n");
を記述しています
このように記述することで
ファイルオープンに失敗したとき
は
ファイルオープンに失敗しましたよ~ん
が
ファイルオープンに成功したとき
は
ファイルオープンに成功しましたよ~ん
がコマンドプロンプト画面に表示されるので
正しくファイルが開けているかをどうかを確認することができます。
それでは例として
数値
1
2
3
を
バイナリファイルTEN-GOGO-C-language.binに保存してみます
そのプログラムは
次のように記述します。
#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};
/*ここに注目
TEN-GOGO-C-language.binファイルにデータを保存したい場合
まず
TEN-GOGO-C-language.binファイルに
書き込みしたい数値
1
2
3
を
fwrite関数をつかって
用意した配列の
配列変数
hairetu[0]
hairetu[1]
hairetu[2]
に格納します*/
fwrite(&hairetu[0],sizeof(int),1,fp);
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
/*このように
fprintf関数のときとは数値をファイルに保存するときの
表記法が大分ことなります
保存したい数値は
まず
配列変数
hairetu[0]
hairetu[1]
hairetu[2]
に格納してから
ハードディスク内のTEN-GOGO-C-language.binファイルに
fwrite関数を用いて
保存されていきます。
*/
fclose(fp);
return 0;
}
コンパイル結果
Hello!ファイルオープンに成功しましたよ~ん
さきのエピソードで見てきたように
テキストファイルのTEN-GOGO-C-language.txtファイルに
数値データ
1
2
3
を
書き込み保存するときは
fprintf関数をもちいて
次のプログラムのように
#pragma warning(disable: 4996)
#include <stdio.h>
int main (void){
FILE *fp;
fp=fopen("TEN-GOGO-C-language.txt","w");
if(fp==NULL){
printf("ファイルオープンに失敗しましたよ~ん\n");
return -1;}
else printf("Hello!ファイルオープンに成功しましたよ~ん\n");
fprintf(fp,"%d\n",1);
fprintf(fp,"%d\n",2);
fprintf(fp,"%d\n",3);
fclose(fp);
return 0;
}
と
記述されていました。
このとき
fprintf関数を用いて
数値
1
2
3
を
ハードディスク内のファイルに書き込む形式は
fprintf(fp,"%d\n",1);
fprintf(fp,"%d\n",2);
fprintf(fp,"%d\n",3);
となっていました
TEN-GOGO-C-language.binファイルに
数値データ
1
2
3
を
バイナリデータ
として書き込み保存する際には
fwrite関数をもちいます。
fwrite関数をつかって数値をハードディスク内のファイルに書き込む形式は
fwrite(&hairetu[0],sizeof(int),1,fp);
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
となります
このとき命令文
fwrite(&hairetu[0],sizeof(int),1,fp);
が行われると
ハードデイスク内のbinファイルの1行目に
アドレス&hairetu[0]のメモリに格納されているデータ
1
が
かきこまれます。
そして次の命令文
fwrite(&hairetu[1],sizeof(int),1,fp);
が行われると
ハードデイスク内のbinファイルの2行目に
アドレス&hairetu[1]のメモリに格納されているデータ
2
がかきこまれます。
このように
fwrite文が1つ実行されるたびに
fwrite文の第1引数のアドレスのメモリに格納されているデータは
1行ごとに
行を変えながら
保存されていきます。
そして
さらに
fwrite(&hairetu[2],sizeof(int),1,fp);
が実行されると
さらに
次の行にアドレス&hairetu[2]のメモリに格納されているデータ
3
が
かきこまれていきます。
このときの
fwrite文
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[0],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
をみてもわかるように
データをbinファイルの次の行に保存するのに
改行するためのエスケープシーケンス\
を記述する必要はないのです。
テキストファイルにデータを保存する
fprintf関数の表記法
fprintf(fp,"%d\n",1);
fprintf(fp,"%d\n",2);
fprintf(fp,"%d\n",3);
と
バイナリファイルにデータを保存する
fwrite関数の表記法
fwrite(&hairetu[0],sizeof(int),1,fp);
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
では表記法が随分異なりますね
この
数値
1
2
3
を
バイナリデータ
として
ファイルに書き込み保存するプログラムでは
🍋 あらかじめ 🍋
配列宣言
int hairetu[]={1,2,3};
を行い
保存したい数値
1
2
3
を
int hairetu[]={1,2,3};
より生成される
配列変数
hairetu[0]
hairetu[1]
hairetu[2]
に
hairetu[0]=1
hairetu[1]=2
hairetu[2]=3
と格納します
hairetu[0]に数値データが
格納されています。
数値データ
1
をそのまま
バイナリファイルに書き込み保存する場合に
用いられるのが
fwrite関数になります。
fwrite関数の第1引数には
fwrite(&hairetu[0],sizeof(int),1,fp);
のように
数値1を格納しているhairetu[0]の
🍅アドレス&hairetu[0]🍅
をかきこみます
2番目の引数には
保存したい数値データが整数の場合 sizeof(int)
保存したい数値データが実数の場合 sizeof(float)
あるいは
sizeof(double)
をかきこみます。
int型は4バイトのデータ格納容量
float型も4バイトのデータ格納容量
double型は8バイトのデータ格納容量
をもつので
変数の型の格納容量をあらわすsizeof演算子により
sizeof(int)
sizeof(float)
sizeof(double)
は
それぞれ
sizeof(int)=4
sizeof(float)=4
sizeof(double)=8
に等しくなります
ですので
fwrite(&hairetu[0],sizeof(int),1,fp);
fwrite(&hairetu[0],sizeof(double),1,fp);
の代わりに
fwrite(&hairetu[0],4,1,fp);
fwrite(&hairetu[0],8,1,fp);
と記述することもできます
この第2引数に書き込まれた数値を単位として
バイナリファイルにバイナリデータは書き込まれていきます
つまり
fwrite(&hairetu[0],4,1,fp);
なら
4バイトのスペースを持つお部屋に
アドレス&hairetu[0]のメモリに格納されている数値データ1
は
格納されます
つまり
バイナリファイルの1行が
4バイトのデータ格納スペースを持つことになります。
fwrite(&hairetu[0],8,1,fp);
なら
8バイトのスペースを持つお部屋にアドレス&hairetu[0]のメモリに
格納されている数値1
は格納されます
つまり
バイナリファイルの1行が8バイトのデータ格納スペースを持つことになります。
そして
fwrite関数の第3引数は
保存したいデータを書き込む回数をあらわしています。
fwrite(&hairetu[0],sizeof(int),1,fp);
と記述されたとき
3番目の引数1は
バイナリファイルに
&hairetu[0]のアドレスのメモリに格納された数値1
を
1回書き込むことを表しています。
fwrite(&hairetu[0],sizeof(int),0,fp);
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
なら
fwrite(&hairetu[0],sizeof(int),0,fp);
の第3引数は0なので
&hairetu[0]のアドレスのメモリに格納された数値1
は
1回もバイナリファイルに書きこまれません。
そして次の命令文
fwrite(&hairetu[1],sizeof(int),1,fp);
により
&hairetu[1]のアドレスのメモリに格納された数値2
は
1回バイナリファイルに書きこまれ
さらに次の命令文
fwrite(&hairetu[2],sizeof(int),1,fp);
により
&hairetu[2]のアドレスのメモリに格納された数値3
も
1回バイナリファイルに書きこまれます。
実際にプログラムを構成して確認してみます。
#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),0,fp);
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
fclose(fp);
return 0;
}
コンパイル結果
Hello!ファイルオープンに成功しましたよ~ん
PC内検索を行うと
バイナリファイル
TEN-GOGO-C-language.bin
が作成されているのがわかります。
しかし
バイナリファイルである
TEN-GOGO-C-language.binファイルは
テキストファイルを開くソフトを使って
開いて中身を閲覧することができない仕様になっていますので
TEN-GOGO-C-language.binファイルに
どんなデータが保存されているかを調べるためには
fread関数を使って
TEN-GOGO-C-language.binファイルからデータを
読み取る必要があります。
fread関数については次のエピソードでお話しますので
続きは後ほどとなります。
fwrite関数の4番目の引数となっている
ファイルポインタ変数fpは
fwrite(&hairetu[0],sizeof(int),1,fp);
が実行されると
int hairetu[]={1,2,3};
により
メモリに格納された数値
1
を
ファイル構造体をとおして
別の
メモリに格納するはたらきをしています
そのメモリのアドレスを
ファイルポインタ変数fpは格納することになります。
そのメモリに格納された
数値データ
1
は
ハードデイスク内のバイナリファイルに
そのまま保存されるという仕組みとなっています
そうして
fwrite(&hairetu[0],sizeof(int),1,fp);
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
が全て実行されると
ハードデイスク内のバイナリファイルに
数値データ
1
2
3
は保存されます。
このように
fwrite関数により保存したいデータが配列から
ファイルポインタ変数fpをつかって
別のメモリに移し替えられた後
ハードディスク内のTEN-GOGO-C-language.binファイルに
その保存したいデータは送り込まれ保存されます
新規書き込みモード"w"のように
新規書き込みモード"wb"でファイルが開かれる場合
以前バイナリファイルに保存されていたデータはすべて消えてしまいます
新規書き込みモード"r"のように
読み込みモード"rb"でファイルが開かれている場合
バイナリファイルからデータの読み込みしかできない状態になっています
バイナリファイルからデータの読み込みを行うときは
ファイルポインタ変数fpの格納しているアドレスのメモリに
バイナリファイルのデータは格納されることになります。
そして
次のエピソードで出てくる
fread関数は
ハードディスクのバイナリファイルのバイナリデータを
ファイルポインタ変数fpの格納しているアドレスのメモリに格納して
さらに
メモリに格納されたバイナリファイルのバイナリデータを
用意した配列の配列変数に移し替えます。
その後
配列変数に格納されたデータをprintf関数を使って
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),0,fp);
fwrite(&hairetu[1],sizeof(int),1,fp);
fwrite(&hairetu[2],sizeof(int),1,fp);
fclose(fp);
return 0;
}
コンパイル結果
Hello!ファイルオープンに成功しましたよ~ん
このバイナリファイルにバイナリデータとしてデータを保存する
プログラムの実行後
TEN-GOGO-C-language.binを
PC内検索にかけて検索すると
バイナリファイルTEN-GOGO-C-language.binが
作成されているのをみつけることができます。
ですが
バイナリファイルをひらいて中身を確認することは
できません。
開こうとしても.bin形式のファイルを開くことはできません
とパソコン画面に表示されます
おしいです・・・」
ソーラー「ほんとだ バイナリファイルを開くには
どうやら専用ソフトでもいるのかな?」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます