ランダムアクセス
ファイルの特定の場所にアクセスする
これまでのファイルの読み取り方は、ファイルの先頭から最後まで順番に行われました
バイトを読み取るごとに、ファイルポインタは次の項目に進みましたね
これを繰り返して、出力したり入力したりしていました
これまでのような、ファイルの先頭から順に読み取るファイル形式をシーケンシャルアクセスと呼びます
単なるテキストデータの場合、これほど効率的な方法はありません
手間もかからず、理想的な読み取り方といえます
しかし、バイナリデータの場合は適しているとは思え難いです
バイナリファイルの場合、その仕様から多くの異なる目的のデータがバイトごとに並んでいることが多いでしょう
このデータをシーケンシャルにアクセスして、目的のデータだけをカットするのは大変手間がかかります
そこで、バイナリファイルの場合は任意の場所からアクセスできると非常に便利です
このような、特定の場所へのファイルアクセスをランダムアクセスと呼びます
特定の位置にアクセスするには、ファイルポインタの位置を任意の場所に変更する必要があります
ランダムアクセスするためにはfseek()関数を使用します
int fseek(FILE *ストリーム , long オフセット , int 初期位置);
ストリームは有効なFILE型構造体変数を指定します
初期位置には、有効な定義済みの定数を指定します
定数はstdio.hで定義されており、次の三つが用意されています
- SEEK_CUR : 現在のファイルポインタの位置
- SEEK_SET : ファイルの先頭
>
- SEEK_END : ファイルの終端
オフセットは、指定した位置からのバイト数を指定します
ファイルポインタは初期位置からオフセットで指定した部分へ移動します
戻り値は、成功すると0を返します。それ以外の場合は0以外です
ランダムアクセスを制御するのに、プログラムによっては
現在のファイルポインタの位置を取得する必要もあるかもしれません
現在のファイルポインタの位置を取得するにはftell()関数を使用します
long ftell( FILE *ストリーム );
この関数は、指定されたストリームのファイルポインタを返します
次のプログラムを実行して、ファイルポインタが移動しているか確認してみましょう
#include <stdio.h>
#include <stdlib.h>
int main() {
char fileName[128];
int fileIndex , text;
FILE *fp;
printf("読み込むファイル名を指定してください>");
scanf("%s" , fileName);
printf("ファイルを読み出す開始位置をバイト単位で指定してください>");
scanf("%d" , &fileIndex);
if ((fp = fopen(fileName , "r")) == NULL) {
fprintf(stderr , "ファイル操作でエラーが発生");
exit(1);
}
fseek(fp , fileIndex , SEEK_SET);
printf("///ファイル位置 %d から読み出します///\n" , ftell(fp));
while(1) {
text = fgetc(fp);
if (!feof(fp)) printf("%c" , text);
else break;
}
fclose(fp);
return 0;
}
指定したファイルを、先頭から指定したバイト数分移動したところから読み込みます
通常はバイナリファイルの操作に使用されますが、このプログラムは実験的なものなので
テキストファイルを読み込んで確認していただいたかまいません
ランダムアクセスを使用すれば、効率的にひとつのファイルのバイナリデータにアクセスできます
実用的なアプリケーションになると、バイナリデータは設定の保存などで使用することになるでしょう
このとき、設定数だけファイルを作るのでは非常に不合理なストリームになります
ランダムアクセスを利用して、ひとつのファイルに対して様々なバイナリデータを保存するのが望ましいですね
次のプログラムは、ファイルの先頭から1キロバイト先にバイナリデータを書きこんでいます
fopen()関数で開くファイルがバイナリデータであることを明示するために、今回は "wb" というような指定をしています
#include <stdio.h>
#include <stdlib.h>
int main() {
int i[] = { 100 , 200 , 300 };
FILE *fp;
if ((fp = fopen("test.txt" , "wb")) == NULL) {
fprintf(stderr , "ファイル操作でエラーが発生");
exit(1);
}
fseek(fp , 1024 , SEEK_SET);
fwrite(i , 4 , 3 , fp);
fclose(fp);
return 0;
}
このプログラムをコンパイルして実行すると
同じディレクトリにtest.txtというファイルが作成されています
このファイルは、バイナリデータなのでテキストエディタで開いても意味のない記号が出力されるだけですが
最初から1キロバイトまでは空白です
ランダムアクセス専用のファイルは、ランダムアクセスという目的である以上読み取る場所を指定します
そのため、書き込まれるデータが可変長の場合は適しません
ランダムアクセスファイルのデータは、レコードが常に固定長である必要があります
int fseek( FILE *stream, long offset, int origin );
指定された位置にファイルポインタを移動させます
ヘッダ - stdio.h
stream - 有効なFILE構造体へのポインタ
offset - originからのバイト数
origin - 初期位置
戻り値 - 成功すると 0 を、それ以外の場合は 0 以外の値を返します
long ftell( FILE *stream );
ファイルポインタの現在の位置を取得します
ヘッダ - stdio.h
stream - 有効なFILE構造体へのポインタ
戻り値 - 現在のファイルポインタの位置を返します。エラーの場合は-1L