fseek関数を用いてバイナリファイルからデータの読み込み開始位置を指定してデータを読みこんでみましょう 読み取り基準位置がSEEK_SETの場合 


アレサ「そして


今度はfseek関数の登場です(#^^#)


fseek関数を用いれば


バイナリファイルからデータを読み込むとき


いつもにように

1行目からでなく

データの読み込み開始位置を


別の行からに指定して

データを読みこむことができます。


まずは

数値

1

2

3

4

5

6

7

をバイナリデータとして


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");

/*新規書き込み機能をもつ"wb"になっていますね*/

if(fp==NULL){

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

return -1;}

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


int hairetu[]={1,2,3,4,5,6,7};

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

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

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

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

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

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

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


fclose(fp);

return 0;

}


コンパイル結果

(EAZY IDECの場合)

(Visual Studioの場合)


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


このプログラムでは

まず

配列宣言

int hairetu[]={1,2,3,4,5,6,7};


をおこない

生成された

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

hairetu[5]

hairetu[6]


数値

1

2

3

4

5

6

7

格納します


そして次に


数値を格納している


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

hairetu[5]

hairetu[6]


のアドレス


&hairetu[0]

&hairetu[1]

&hairetu[2]

&hairetu[3]

&hairetu[4]

&hairetu[5]

&hairetu[6]


をfwrite関数の第1引数に指定して


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

hairetu[5]

hairetu[6]

が格納している

数値

1

2

3

4

5

6

7


をバイナリファイルに


1  (ファイルの1行目)

2  (ファイルの2行目)

3  (ファイルの3行目)

4  (ファイルの4行目)

5  (ファイルの5行目)

6  (ファイルの6行目)

7  (ファイルの7行目)


と保存していきます


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


と第2引数にsizeof(int)が記述されているので


このバイナリファイルの1行は sizeof(int)=4バイトのデータ格納容量を持つようになります


🌞  🌞  🌞



このバイナリファイルに

1  (ファイルの1行目)

2  (ファイルの2行目)

3  (ファイルの3行目)

4  (ファイルの4行目)

5  (ファイルの5行目)

6  (ファイルの6行目)

7  (ファイルの7行目)


保存されたデータを読み込んで


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


数値

1

2

3

4

5

6

7

を表示するには


fread関数をもちいます。


プログラムは次のようになります



#pragma warning(disable: 4996)

#include <stdio.h>

int main (void){


FILE *fp;

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


/*バイナリファイルからデータを読み込むので

オープンモード"rb"がもちいられています*/


if(fp==NULL){

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

return -1;}

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


int hairetu[7];

/*この配列宣言により

生成される

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

hairetu[5]

hairetu[6]

にバイナリファイルのデータを格納していきます*/


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

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

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

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

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

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

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


/*そして配列の中身をprintf関数によってコマンドプロンプト画面に

表示していきます*/

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

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

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

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

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

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

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

fclose(fp);

return 0;

}


コンパイル結果


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

1

2

3

4

5

6

7


アレサ「


このときバイナリファイルのデータを


fread関数は


数値1から読み込み


配列に格納しはじめています。」


ソーラー 「それはfscanf関数のときでも


そうだったけど


いつものことじゃない?


バイナリファイルには

1  (ファイルの1行目)1行はsizeof(int)=4バイトの容量があります

2  (ファイルの2行目)1行はsizeof(int)=4バイトの容量があります

3  (ファイルの3行目)1行はsizeof(int)=4バイトの容量があります

4  (ファイルの4行目)1行はsizeof(int)=4バイトの容量があります

5  (ファイルの5行目)1行はsizeof(int)=4バイトの容量があります

6  (ファイルの6行目)1行はsizeof(int)=4バイトの容量があります

7  (ファイルの7行目)1行はsizeof(int)=4バイトの容量があります


と数値データが格納されていて


fread関数により


その数値データが1から順に


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

hairetu[5]

hairetu[6]


に格納されてから


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

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

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

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

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

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

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

により

コマンドプロンプト画面に表示されていくんだよね。」



アレサ「その数値の読み取り開始位置を



  🍓バイナリファイルからデータをよびだす際に限り🍓



例えば


読み取り開始位置を3行目の前に変更し


3から


3

4

5

6

7

読み込んでいくことが可能なのです。



   😝テキストファイルからデータをよびだす場合は😝


   😝数値の読み取り開始位置を変更できないのです。😝





🐦🐦🐦

バイナリファイルに保存されているデータからは


読み取り開始位置を指定してデータをよびだすことができます


読み取り開始位置を指定してデータをよびだす方法を


ランダムアクセスとよびます。


が 


読み取り開始位置を指定しているので全然ランダムでないのです

🐦🐦🐦


バイナリファイルから読み取り開始位置を


指定してデータをよびだすには


fseek関数をもちいます。


fseekは


file seekの略です


🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲

seekは英語で さがす という意味で


コンピュータ用語では


シークするといえば


読み書きする装置のヘッドが読み書き位置まで移動する


ことを表しています。

🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲🌳🌲


fseek関数には3つの引数があり


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


書きかきっ



fseek(

fp,第1引数です

読み込み開始位置と読み取り基準となる位置の差第2引数です(読み取り基準となる位置からどれくらい離れているかをあらわす。),

読み取り基準となる位置第3引数です



第1引数は ファイルポインタ変数 fp

第2引数は 読み込み開始位置と読み取り基準となる位置の差(読み取り基準となる位置から読み込み開始位置がどれくらい離れているかをあらわしています。)

第3引数は 読み取り基準となる位置


を書き込むようになっています


                       solarplexussより


アレサ「

fseek関数の

第1引数にはハードディスクのバイナリファイルの


バイナリデータを格納するメモリの


アドレスを格納するファイルポインタ変数 fpを記述します.


次に


第2引数 読み込み開始位置と読み取り基準となる位置の差(読み取り基準となる位置から読み込み開始位置がどれくらい離れているかをあらわしています。)

第3引数 読み取り基準となる位置


の説明となるのですが


分かりやすく


まず第3引数から御説明いたします。



第3引数には

読み取り基準となる位置として


位置情報を表す

SEEK_SET

SEEK_CUR

SEEK_END


のうちのどれかが記入されます。」


ソーラー「読み取り基準となる位置?


読みこみ開始位置?


の2つがなぜあるのかな?


なんか この2つの違いが分からない…」


アレサ「そうですね。


このままではわかりにくいです。


まずは読み取り基準となる位置について


ご説明いたします


バイナリファイルはデータが


1行ごとに管理されています。


SEEK_SET

SEEK_CUR

SEEK_END

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

とある位置をあらわしています


ここで

SEEK_SETの位置が


どこにあたるかを


今、

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

1

2

3

4

5

6

7

をもちいて説明いたします。


ソーラー「お願い💖」


アレサ「はいっ😊


では、わかりやすく


SEEK_SETの位置にあたる場所を図で表してみます。


図でみると


数値データ1の前の最初の位置が


SEEK_SETの位置にあたります。」



最初の位置_________ <<<SEEK_SET🌞

1行目     

______________

2行目     

______________

3行目     

______________

4行目     

______________

5行目    

______________

6行目     

______________

7行目     

最後の位置_________<<<SEEK_END


ソーラー「SEEK_SETは


1行目の手前すぐの位置にあたるんだ・・・


まあ


1行目より前の位置じゃないと


1行目のデータがよみこめないのかな・・・」


アレサ 「SEEK_ENDは


7行目のすぐ後の


データの最後の位置をあらわします。」


ソーラー「は~い」


アレサ 

「SEEK_CURの位置はあとで・・・説明を・・・


でも全然むずかしくありません」


ソーラー 「は~い」


アレサ「それでは


fseek関数(fp,読み込み開始位置と読み取り基準となる位置の差(読み取り基準となる位置からどれくらい離れているかをあらわす。),読み取り基準となる位置)の


第3引数である


読み取り基準となる位置を SEEK_SETに設定して


お話を進めてみます。




第3引数はSEEK_SETとした後


次は


第2引数を次の例のように記述していきます。


例1.fseek(fp,sizeof(int),SEEK_SET)

例2.fseek(fp,2*sizeof(int),SEEK_SET)

例3.fseek(fp,3*sizeof(int),SEEK_SET)


などなど・・・


。。。。。。。。。。。。。。。。。。。。。。。。。。



バイナリファイルに数値データ


1

2

3

4

5

6

7


が書き込まれる際

fwriteの第2引数に


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


のように


sizeof(int)=4バイトが設定されたので


バイナリファイル内の1行は

次の図のように

1行ごとに4バイトのデータ量を持っていることになります


最初の位置_________SEEK_SET

1行目     sizeof(int)=4バイト

______________

2行目     sizeof(int)=4バイト

______________

3行目     sizeof(int)=4バイト

______________

4行目     sizeof(int)=4バイト

______________

5行目     sizeof(int)=4バイト

______________

6行目     sizeof(int)=4バイト

______________

7行目     sizeof(int)=4バイト

最後の位置_________SEEK_END



数値

1

2

3

4

5

6

7

それぞれ

バイナリファイルの

sizeof(int)=4バイトの容量を持つ

1行ごとに格納されています。


sizeof演算子は


変数の型の容量


すなわち


変数の型のデータを格納できるバイト数を表すことができ


int型は4バイトのデータ容量をもつので

sizeof(int)なら

sizeof(int)=4 と

sizeof(int)は

数値4をあらわします。


ですが

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


で用いられた


fwrite関数のsizeof(int)


fseek(fp,sizeof(int),SEEK_SET)


で用いられる


fseek関数のsizeof(int)とは関係ありません


では

fseek関数の

第2引数、第3引数が


例1.fseek(fp,sizeof(int),SEEK_SET)

例2.fseek(fp,2*sizeof(int),SEEK_SET)

記述されたとき


どのような命令が実行されるのかをみていきましょう。


例2では

sizeof(int) には2*と数値2がかけられています。


int型のデータ格納容量は4バイトなので

sizeof(int) はint型のデータ格納容量 4

2*sizeof(int)はint型のデータ格納容量 2個分の容量 8

3*sizeof(int)はint型のデータ格納容量 3個分の容量12


をあらわすことになります。


例1.


       fseek(fp,sizeof(int),SEEK_SET);


ならば


この命令文は


読み取り基準となる位置SEEK_SETから


sizeof(int)

つまり

int 1個分の幅

4バイト分後ろに離れた位置を


読み取り開始位置に指定することを表しています。


ここでようやく

読み取り開始位置が出てきました。



図でしめすなら😊😊😊😊😊😊😊の位置が


読み取り開始位置に指定されます


最初の位置_________SEEK_SET(読み取り基準位置)

1     sizeof(int)=4バイト

______________😊😊😊😊😊😊😊

2     sizeof(int)=4バイト

______________

3     sizeof(int)=4バイト

______________

4     sizeof(int)=4バイト

______________

5     sizeof(int)=4バイト

______________

6     sizeof(int)=4バイト

______________

7     sizeof(int)=4バイト

最後の位置_________SEEK_END



この図のように

数値

1

2

3

4

5

6

7



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


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

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

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

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

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

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

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

のように


fwrite関数の第2引数を


sizeof(int)=4に設定していたので


バイナリファイルの1行はsizeof(int)=4バイトという


データ格納容量をもち


sizeof(int)=4バイトのデータ格納容量をもつ


バイナリファイルの1行ごとに


数値

1

2

3

4

5

6

7

格納されています。



(もし

fwrite関数の第2引数を


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

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

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

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

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

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

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

のように


2*sizeof(int)=8バイトに設定したなら


バイナリファイルの1行は

2*sizeof(int)=8バイトという


データ格納容量を持つようになります。)



そこで


バイナリファイルの1行がsizeof(int)=4バイトというデータ格納容量


を持っているとき



      fseek(fp,sizeof(int),SEEK_SET); 


のように


数値1が格納されている1行目の前の


位置にあたるSEEK_SETを第3引数に記述して


読み取り基準位置とし


🍎読み込み開始位置と読み取り基準となる位置の差🍎


を表す


sizeof(int)を


第2引数に記述すると


読み取り基準位置SEEK_SETから


sizeof(int)=4バイト 1個分の幅、後ろに離れた位置を


読み取り開始位置😊😊😊😊😊😊😊


に指定することになります


つまり👆の図のように


数値2が格納されている2行目の前の位置が


読み取り開始位置😊😊😊😊😊😊😊となります。



例2.


     fseek(fp,2*sizeof(int),SEEK_SET)


と記述されたなら


読み取り基準となる位置SEEK_SETからsizeof(int) 2個分の幅


後ろに離れた位置を


読み取り開始位置😊😊😊に指定することになります。


図でしめすなら😊😊😊の位置が


読み取り開始位置😊😊😊に指定されます。


最初の位置_________SEEK_SET

1     sizeof(int)=4バイト

______________

2     sizeof(int)=4バイト

______________読み取り開始位置😊😊😊

3     sizeof(int)=4バイト

______________

4     sizeof(int)=4バイト

______________

5     sizeof(int)=4バイト

______________

6     sizeof(int)=4バイト

______________

7     sizeof(int)=4バイト

最後の位置_________SEEK_END



ソーラー「こうやってfseek関数をつかって


読み取り開始位置を指定するんだ・・・」


アレサ「そこで


実際にfseek関数を使ったプログラムを組み、


バイナリファイルのデータの読み取り開始位置を指定してから


データを


読み取っていきたいとおもいます。


ここでは


例2.fseek(fp,2*sizeof(int),SEEK_SET)をプログラムに


もちいて


👇の図で表されているように


読み取り開始位置😊😊😊😊😊を数値3の前に指定します。



最初の位置_________SEEK_SET

1     sizeof(int)=4バイト

______________

2     sizeof(int)=4バイト

______________読み取り開始位置😊😊😊😊😊

3     sizeof(int)=4バイト

______________

4     sizeof(int)=4バイト

______________

5     sizeof(int)=4バイト

______________

6     sizeof(int)=4バイト

______________

7     sizeof(int)=4バイト

最後の位置_________seek_end



では


読み取り開始位置😊😊😊😊😊を指定したところで


3から始めて

3

4

5

と数値データを


バイナリファイルから呼び出してみましょう。



まずはいつもどおり


数値

1

2

3

4

5

6

7


fwrite関数を使った次のプログラムで


バイナリデータとして


バイナリファイルである


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");

/*データを書き込むのでオープンモード"wb"で

バイナリファイルをひらいています*/

if(fp==NULL){

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

return -1;}

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

int hairetu[]={1,2,3,4,5,6,7};

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

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

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

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

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

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

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


fclose(fp);

return 0;

}


コンパイル結果

(EAZY IDECの場合)

(Visual Studioの場合)


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


アレサ「ファイルオープンに成功💖


これで

数値

バイナリデータに変換して

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


これで 準備段階はおわりました


では

fseek関数を使って


読み取り開始位置を3が格納されている3行目の前に指定する


fseek(fp,2*sizeof(int),SEEK_SET)を


使用した


次のプログラムを用いて


数値


をバイナリファイルからよびだして


コマンドプロンプト画面にprintf出力表示してみます。


#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];

/*数値

3

4

5

を格納するために

配列宣言

int hairetu[3];

をおこない

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

を作製しました

*/


fseek(fp,2*sizeof(int),SEEK_SET);

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!ファイルオープンに成功しましたよ~ん

3

4

5


ソーラー「おおお、成功している。


さりげなくすごくない?」


アレサ 「


この時

数値データ

3

4

5

を格納するために



配列宣言int hairetu[3];

をおこない

配列変数

hairetu[0]

hairetu[1]

hairetu[2]


作製しています。


バイナリファイルからの数値データ


3

4

5

fread関数により


配列変数

hairetu[0]

hairetu[1]

hairetu[2]


hairetu[0]=3

hairetu[1]=4

hairetu[2]=5


と格納されています。


つまり

バイナリファイルからデータの読み込みは

fread関数がおこない


データ読み込み開始位置を

fseek関数が指定しているというわけです。



fseek関数が使われない


いつもどおりの


fread関数のみを用いた次のプログラムでは


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

となり


いつもどおり


fread関数による

バイナリファイルからの数値データ読み込みは

1から始まり


hairetu[0]

hairetu[1]

hairetu[2]

には


バイナリファイルからの数値データが

hairetu[0]=1

hairetu[1]=2

hairetu[2]=3

と格納されているのがわかります。


データの読み込み開始位置が


fseek関数により


3を格納している3行目の前に指定されたときとは


hairetu[0]

hairetu[1]

hairetu[2]に


格納されている数値が違うのがわかりますね。


このように


fseek関数は


ファイルポインタ変数fpが


ハードディスクのTEN-GOGO-C-language.binファイルから


メモリにデータを格納する際


ファイルポインタ変数fpがどのデータから


メモリに読み込みを開始するかを指定しているのですの」




ソーラー「もしかして


バイナリファイルからのデータ呼び出しの際


このfseek関数のようなデータ読み出し開始位置指定機能があるということは


この読み出し開始位置を指定する機能を必要とする機器があったんじゃないかな?


だからこそ


このfseek関数はつくられた。


読み出し開始位置を指定する機能を必要とする


その機器の名は・・・」



アレサ「機器の名は・・・」













ソーラー「機器の名はロードローラーです」













アレサ「ロードローラーでなく機器の名はCDプレーヤーです」


ソーラー「はっ?・・・・・・・・・

・・・・・・・・・・・・・・


ロードローラーは


読み出し開始位置を指定する機能を必要としないのか・・・


あ、ちょっと、そうか いまわかったよ」


アレサ「いくつかの小型の機器を


動作させるのにC言語を使ってプログラムが作製されているとききます。


fseek関数さん 大活躍ですね😊」




🌳🌳🌳

みなさ~ん こんにちは~~~


小型の機器を動作させるのにプログラムが作製されていると


いわれても


例えば


炊飯ジャーやCDプレーヤーをみても


どこにプログラムがつかわれてるの?


とおもわれるかもしれません。


そのようなときは


お使いのパソコンの電源は切らず


お使いのパソコンのモニター画面表示を消した状況を


考えて見られれば


よくおわかりになられると思います。


モニターを消しても


もっといえば


モニターが無くても


キーボードのボタン操作だけで


パソコンでCDを再生し音楽を鳴らすことができますね。


このとき


パソコンはボタンを操作するとCDを再生するという


あらかじめ設定されたプログラムから命令を受け


CDの再生を実行しています。


それと同じように


モニターがないだけで


さまざまな機器がプログラムから命令を受け動作しています。


                   solarplexussより


























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

作者を応援しよう!

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

応援したユーザー

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