ファイルのランダムアクセス

このエントリーをはてなブックマークに追加

今回は今まで説明していなかったファイル操作であるランダムアクセスについて解説します。
使用頻度はread(2)、write(2)系関数に比べると落ちますが、特定のファイル構造にアクセスするときなど、高速化が求められる場合に場合使用します。
ちなみに、通常のアクセス方法はシーケンシャルアクセスと言います。

ランダムアクセス

標準関数のおさらい

まずは標準をおさらいします。

関数名説明
fseek(3)カレントポジションの位置を指定に移動します
ftell(3)カレントポジションの位置を取得します
rewind(3)カレントポジションの位置をファイル先頭位置に移動します
fgetpos(3)ftell(3)とほぼ同じ動作。ftell(3)で存在するサイズ制限を気にしなくてもよい
fsetpos(3)fseek(3)とほぼ同じ動作。ftell(3)で存在するサイズ制限を気にしなくてもよい

fgetpos(3)、fsetpos(3)は入門用の解説書などでは出てこないかもしれませんので少し追加説明をしておきます。 fseek(3)、ftell(3)ではサイズ位置を表す型はlongとなっています。これは2147483647が最大ですが、これをファイルサイズに直すと2G-1バイトです。とてもでは無いですが最近のハードウェア上では通用しないです。
これを解決するために、さらに大きなサイズに対応したfgetpos(3)等があります。


システム関数のランダムシーク

システム関数のランダムシークに当たるのはlseek(2)のみとなります。
つまり、先ほど紹介したすべての関数はlseek(2)を使って作成されています。


では、lseek(2)、lseek64(2)のプロトタイプです。
//32bit
#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

//64bit
#define _LARGEFILE64_SOURCE
#include <sys/types.h>
#include <unistd.h>

off64_t lseek64(int fd, off64_t offset, int whence);

offsetはファイル位置を指定します。
whenceに指定する値によって変わります。whenceに指定する値は次のとおりです。

whence説明
SEEK_SETオフセットはoffsetバイトに設定されます
SEEK_CURオフセットは現在位置にoffsetバイトを足した位置になります
SEEK_ENDオフセットはファイルのサイズにoffsetバイトを足した位置になります

off_tは32bitシステム上で扱える最大値まで使用できます。
ちなみに、64bit上ではlseek64(2)が存在します。


サンプルコード

では、サンプルコードです。コメントを入れているので解説は必要ないと思いますので省略します。
//file_pos.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(void)
{
  int fd;
  off_t pos;

  fd = open("test.txt", O_RDONLY);
  if (fd < 0) {
    return 1;
  }

  //ファイルサイズを取得する
  pos = lseek(fd, 0, SEEK_END);
  printf("file size:%ld\n", pos);

  //ファイルの先頭に移動する:rewind(3)と同様
  pos = lseek(fd, 0, SEEK_SET);

  //現在のファイル位置を取得する:lseek(3)と同様
  pos = lseek(fd, 0, SEEK_CUR);
  printf("file pos:%ld\n", pos);

  return 0;
}

では実行してみます。
$ gcc -o file_pos file_pos.c
$ ./file_pos
file size:512
file pos:0