標準ファイル入出力3
■この章で解説する組み込み関数
read, seek, tell
■この章でできること
・バイト単位のファイルの読み書きをする
・ファイルポインタの現在の位置を取得する
・ファイルの任意の位置にシークする

 標準ファイル入出力2では、行単位のファイル入出力の解説をしましたが、バイト単位で読み書きをしたり、ファイルの任意の位置から読みこんだり、任意の位置に書き込みをしたい場合もあります。ここでは標準ファイル入出力を使って、そのようなファイル入出力をする方法を解説します。

 では、まずはサンプルソースから見てみましょう。

#!/usr/bin/perl

#############################################
# 標準ファイル入出力のサンプル5
# Author: "Perl Programming Tips"
#############################################

# 読み書き用にオープン
open(HFILE, "+<file03_01.txt") or die($!);

# ファイル内容を読み込み
$byte = read(HFILE, $data, 4);
die($!) if ($byte == undef);
print "$data\n";

# ファイルポインタの位置を取得
$pt = tell(HFILE);
$data = <HFILE>;
print "$data";

# シーク
seek(HFILE, $pt, 0) or die($!);

# 書き込み
print(HFILE "w") or die($!);

# シーク
seek(HFILE, $pt, 0) or die($!);
$data = <HFILE>;
print "$data";

# クローズ
close(HFILE);

 実行結果は次のようになります。

[g@630m pl]$ cat file03_01.txt
abcdefg
hijklmn
opqrstu
[g@630m pl]$ perl file03_01.pl
abcd
efg
wfg
[g@630m pl]$

 最初にファイルからバイト数を指定して読み込んでいます。その後ファイルポインタを使って、ファイルの特定の位置への書き込み、特定の位置からの読み込みを行っています。

 ファイルの現在の位置からバイト数を指定して読み込むには、read関数を使います。

read
指定したファイルハンドルから、指定したバイト数のデータを読み込む。
書式
read filehandle, $var, length, [offset]
引数
filehandle:
ファイルハンドル
$var:
読み込みバッファ
length:
読み込むバイト数
offset:
指定した場合は、$varのoffset位置に読み込まれる。
戻り値
実際に読み込んだバイト数。end-of-fileの場合は0、エラーの場合は未定義値。

 これに対して、ファイルの任意の位置への任意バイトの書き込みはprint関数を使います。print関数はバイト数を指定しなくても書き込むデータの長さを判断できるためです。

 現在のファイルポインタの位置を取得するには、tell関数を使います。この関数で得た値をその後のseek関数で利用しています。

tell
指定したファイルハンドルの、現在のファイルポインタの位置を返す。
書式
tell filehandle
引数
filehandle:
ファイルハンドル
戻り値
ファイルハンドルの現在のファイルポインタ位置

 ファイルポインタを使ってファイルの中をシークするには、seek関数を使います。

seek
指定したファイルハンドルのファイルポインタを指定した位置にシークする。
書式
seek filehandle, offset, whence
引数
filehandle:
ファイルハンドル
offset:
whenceからのオフセット位置
whence:
0の場合ファイルの先頭、1の場合現在の位置、2の場合ファイルの末尾
戻り値
成功した場合1、失敗した場合0

 whenceが1または2の場合は、offsetに負の値を指定できます。

 上のサンプルでは、ファイルの同じ位置に2回シークして、書き込み前と書き込み後の同じ位置のデータを出力しています。