seek

ファイルハンドルのポインタ移動する

構文

解説

seek は、FILEHANDLE のファイルポインタをバイト位置でセットします。 POSITION はバイト数による位置を表しますが、バイトをどこから数えるのかを WHENCE で指定します。 0 ならファイルの先頭から数えます。1 なら現在のファイルポインタの位置から数えます。 2 ならファイルの最後から数えます。しかし、逆方向に数えなければならないため、POSITION には負の値を指定します。

次の例は、UTF-8 で "あいうえおかきくけこ" と書かれたテキストファイルをオープンし、 seek を使ってファイルポインタを先頭から 6 バイト移動します。 そして、read を使って 3 文字分だけ読み取っています。

open my $fh, '<:utf8', './sample.txt';    # "あいうえおかきくけこ"
seek $fh, 6, 0;                           # ファイルポインタを先頭から 6 バイト移動する
read $fh, my $str, 3;                     # ファイルポインタの位置から 3 文字を読み取る
utf8::encode($str);                       # Perl 内部文字列を UTF-8 外部文字列に変換
print $str, "\n";                         # "うえお"

このコードは "うえお" と出力します。この結果を不思議に思うかもしれません。 utf8 モードでオープンされたファイルハンドルから read を使ってデータを読み取る際に、取り出すデータ長は文字数で指定します。 そのため、seek の引数の単位も文字数と思われるかもしれません。 しかし、実際には seek の引数の単位はバイトですので注意が必要です。 残念ながら、文字数を単位にしてファイルポインタを移動する手段は用意されていません。

前述のサンプルコードは seek を使って 6 バイトだけファイルポインタを移動しました。 ファイルの文字エンコーディングは UTF-8 のため、たまたま「ひらがな」なら 2 文字分だったというわけです。 ちょうど文字の区切りの位置にポインタが移動したため、read で都合よく文字を読み取れたのです。 もしファイルポインタが文字の途中に移動すると、そこから取り出される文字は文字化けするはずです。

Fcntl モジュールを使うと、 WHENCE に定数 SEEK_SET (0), SEEK_CUR (1), SEEK_END (2) を使うことができます。

use Fcntl 'SEEK_SET';
seek $fh, 6, SEEK_SET;

seek は成功すれば 1 を返し、失敗すれば 0 を返します。 sysseek は移動後のファイルポインタの位置を返しますが、 seek はそうではありませんので注意してください。

もし、ファイルハンドルを sysreadsyswrite で操作する場合は、 seek は使わないでください。 seeksysseek もファイルポインタをバイト単位で移動する点では違いはありませんが、 PerlIO レイヤーを通すか通さないか、という違いがあります。 この違いによって予期せぬ結果を招く恐れがあります。 ファイルハンドルを sysreadsyswrite で操作する場合は sysseek を使ってください。