ランダムアクセス

fread() はストリームの「現在位置」からデータを読み込む。任意の位置のデータを読み込むためにはこの「現在位置」を動かしてやる必要がある。
fseek() はそのための関数だ。

int fseek(FILE *ストリーム, long オフセット, int 開始位置);

fseek() は「開始位置」から「オフセット」バイトだけ「現在位置」を移動する。「開始位置」は次のマクロのどれかでなければいけない。

SEEK_SETファイルの先頭から
SEEK_CUR現在位置から
SEEK_ENDファイルの終わりから

これらのマクロは stdio.h で定義されている。

fseek() は成功すると 0 を返し、失敗すると 0 以外の値を返す。

ところで、ファイルの現在位置を知りたいときは ftell() を使う。

long ftell(FILE *ストリーム);

ftell() は成功すると現在位置を返し、失敗すると -1 を返す。

次のプログラムは、10 個のデータ(double型)をファイルに書き込み、ファイルを開き直す。そして何番目のデータを表示したいかをユーザーに尋ねて、それを表示する。

#include <stdio.h>
#include <stdlib.h>

double d[10] = {
    10.23,
    19.87,
    1002.23,
    12.9,
    0.897,
    11.45,
    75.34,
    0.0,
    1.01,
    875.875
};

int main(void)
{
    long loc;
    double value;
    FILE *fp;

    /* write array data */
    if ((fp = fopen("myfile", "wb")) == NULL) {
        printf("Cannot open file.\n");
        exit(1);
    }

    if (fwrite(d, sizeof d, 1, fp) != 1) {
        printf("Error: at writing.\n");
        exit(1);
    }
    fclose(fp);

    /* re-open file */
    if ((fp = fopen("myfile", "rb")) == NULL) {
        printf("Cannot open file.\n");
        exit(1);
    }

    printf("What number of element? [0-9] ");
    scanf("%ld", &loc);
    if (fseek(fp, loc * sizeof(double), SEEK_SET)) {
        printf("Seek error.\n");
        exit(1);
    }

    fread(&value, sizeof(double), 1, fp);
    printf("Element %ld is %f\n", loc, value);

    fclose(fp);

    return 0;
}

47 行目で fseek() を使っている。loc に double 型のサイズをかけて、移動すべきバイト数を求めている。

実行例:

takatoh@nightschool $ ./sample_9_6
What number of element? [0-9] 4
Element 4 is 0.897000