14. ライブラリ関数(8/36) - 入出力ライブラリ(7/10)
14.11 ファイル内の位置操作関数
入力関数でファイルから入力すると、通常はファイルの先頭のデータから順番に入力します。これは自動的に行われるため、入力関数を呼び出す度に次のデータを読むことができます。通常はこれで問題は無いと思いますが、ファイルの先頭からではなく、途中のデータを直接入出力したいような場合もあります。そのような場合は、ここで紹介する関数を使うとよいでしょう。
14.11.1 fseek関数
fseek関数はファイルポインタに対応したファイルの入出力位置(ファイルオフセット)を設定します。
【表14-1-30】 fseek関数
形式 | #include <stdio.h>
int fseek(FILE *fp, long offset, int whence); |
返り値 | 正常に処理ができた場合は0を返します。エラーの場合は-1を返します。 |
引数 |
- FILE *fp
- 入出力位置を設定するファイルのファイルポインタを指定します。
- long offset
- 新たに設定する入出力位置をバイト単位で指定します。位置の指定方法は第3引数のwhenceにより異なります。
- int whence
- 第2引数のoffsetの値が何処を起点としたものかを指定します。SEEK_SETはファイルの先頭を、SEEK_CURは現在の位置を、SEEK_ENDはファイルの末尾を起点とする事を表します。
|
使用法、 他 |
正常に処理ができた場合は入出力位置に位置付いていますので、引き続き入出力関数により入出力を行います。 |
14.11.2 ftell関数
ftell関数はファイルポインタに対応したファイルの現在の入出力位置を取得します。
【表14-1-31】 fftell関数
形式 | #include <stdio.h>
long ftell(FILE *fp); |
返り値 | 正常に処理ができた場合は、現在の入出力位置を返します。エラーの場合は-1を返します。 |
引数 |
- FILE *fp
- 入出力位置を取得するファイルのファイルポインタを指定します。
|
14.11.3 rewind関数
rewind関数はファイルポインタに対応したファイルの入出力位置をファイルの先頭に設定します。
【表14-1-32】 rewind関数
形式 | #include <stdio.h>
void rewind(FILE *fp); |
返り値 | ありません。 |
引数 |
- FILE *fp
- 入出力位置をファイルの先頭に設定するファイルのファイルポインタを指定します。
|
使用法、 他 |
この関数の実行後は入出力位置がファイルの先頭になっていますので、入出力関数を実行するとファイルの先頭から処理を行います。
|
14.11.4 例題
前ページの例題(ex14_1_9.prg)で作成したバイナリファイル(ex14_1_9_out.dat)のレコード番号を入力して、そのレコードの内容を標準出力に編集出力します。
#include <stdio.h>
/* 個人情報構造体 */
struct person_info {
int number; /* 番号 */
double weight; /* 体重 */
double height; /* 身長 */
char blood[4]; /* 血液型 */
};
int main(void)
{
FILE *fp_in;
char in_file[] = "./DATA/ex14_1_9_out.dat";
struct person_info person;
char ans[10] = "y";
int number;
long offset;
int return_code = 0;
if((fp_in = fopen(in_file, "r")) != NULL)
{
while(ans[0] == 'y' || ans[0] == 'Y')
{
printf("番号を入力してください ==> ");
scanf("%d", &number);
/* 指定されたレコード位置の設定 */
offset = sizeof(person) * (number - 1);
if(fseek(fp_in, offset, SEEK_SET) == 0)
{
/* レコードを入力 */
if(fread(&person, sizeof(person), 1, fp_in) == 1)
{
/* レコードの内容を出力 */
printf("%-4s %-8s %-8s %s\n", "番号", "体重", "身長", "血液型");
printf(" %03d %6.1f %6.1f %s\n",
person.number, person.weight, person.height, person.blood);
}
else
{
printf("指定された番号のレコードはありません。\n");
}
}
else
{
printf("入力位置の設定が出来ませんでした。\n");
}
printf("処理を続けますか(y/n) ==> ");
scanf("%s", ans);
}
fclose(fp_in);
}
else
{
printf("%sがオープン出来ませんでした。\n", in_file);
return_code = 1;
}
return return_code;
}
$ ./ex14_1_10.prg
番号を入力してください ==> 3
番号 体重 身長 血液型
003 43.2 156.5 AB
処理を続けますか(y/n) ==> y
番号を入力してください ==> 5
番号 体重 身長 血液型
005 75.7 166.5 A
処理を続けますか(y/n) ==> y
番号を入力してください ==> 1
番号 体重 身長 血液型
001 67.0 188.0 A
処理を続けますか(y/n) ==> y
番号を入力してください ==> 0
入力位置の設定が出来ませんでした。
処理を続けますか(y/n) ==> y
番号を入力してください ==> 6
指定された番号のレコードはありません。
処理を続けますか(y/n) ==> y
番号を入力してください ==> -3
入力位置の設定が出来ませんでした。
処理を続けますか(y/n) ==> n
- 30行目
- ファイルの先頭を起点として、指定されたレコード位置に位置付けます。先頭からの距離は前の行で変数offsetに求めています。
- 33行目
- 30行目のfseek関数で入力位置に位置付いていますので、ここで1レコード入力します。
14.11.5 fgetpos関数
fgetpos関数はftell関数と同じく、ファイルポインタに対応したファイルの現在の入出力位置(ファイルの先頭を起点とする)を取得します。ftell関数との相違は、ftell関数は入出力位置をlong int型で返すため、ファイルの大きさは約2GBまで(long int型が4バイト長の場合)となります。これに対して、fgetpos関数は入出力位置を専用の構造体で管理することにより、2GB以上のファイルも取り扱えるようになっています。
【表14-1-33】 fgetpos関数
形式 | #include <stdio.h>
int fgetpos(FILE fp, fpos_t *pos); |
返り値 | 正常に処理ができた場合は0を返します。エラーの場合は-1を返します。 |
引数 |
- FILE *fp
- 入出力位置を取得するファイルのファイルポインタを指定します。
- fpos_t *pos
- 入出力位置を格納するfpos_t構造体変数を指定します。
|
14.11.6 fsetpos関数
fsetpos関数はfseek関数と同じく、ファイルポインタに対応したファイルの入出力位置を設定します。fseek関数との相違は、2GB以上のファイルも取り扱えるようになっていることです。
【表14-1-34】 fsetpos関数
形式 | #include <stdio.h>
int fsetpos(FILE fp, fpos_t *pos); |
返り値 | 正常に処理ができた場合は0を返します。エラーの場合は-1を返します。 |
引数 |
- FILE *fp
- 入出力位置を設定するファイルのファイルポインタを指定します。
- fpos_t *pos
- 新たに設定する入出力位置が格納されているfpos_t構造体変数を指定します。
|