IO::Fileのprintflushとファイルロック

「続・初めてのPerl」を読んでいて、IO::Fileモジュールが出てきたので、使い方を勉強しました。

#!/usr/bin/perl

use strict;
use warnings;
use IO::File;
use Fatal qw/ open close /;

# ファイルの配列
my @files = ( "test_1.txt",
              "test_2.txt",
              "test_3.txt",
              "test_4.txt", 
              "test_5.txt", 
              "test_6.txt", 
            );

# 読み込みのファイルハンドル
my $r_io = IO::File->new($files[0], "r");
print <$r_io>;
$r_io->close;

# 一行ずつ読み込む
$r_io = IO::File->new($files[1], "r");
my @lines = $r_io->getline;
$r_io->close;
print @lines;

# 全行読み込む
$r_io = IO::File->new($files[2], "r");
@lines = $r_io->getlines;
$r_io->close;
print @lines;

# 上書きして書き込む
my $w_io = IO::File->new($files[3], "w");
&write_test($w_io);
$w_io->close;

# 追記して書き込み
$w_io = IO::File->new($files[4], "a");
&write_test($w_io);
$w_io->close;

# ファイルをロックしてから追記する
use Fcntl qw/ :flock /;

my $w_io_0 = IO::File->new($files[5], "a");
flock($w_io_0, LOCK_EX);
&write_test($w_io_0);

# ロックしているから割り込みできない
my $w_io_1 = IO::File->new($files[5], "a");
$w_io_1->print("割り込みできてないよね?(print)\n");

# ロックしていても割り込みして書き込む
my $w_io_2 = IO::File->new($files[5], "a");
$w_io_2->printflush("割り込みできてるよね?(printflush)\n");

flock($w_io_0, LOCK_UN);
$w_io_0->close;
$w_io_1->close;
$w_io_2->close;

# ファイル書き込みのテストサブルーチン
sub write_test {
    my $w_io = $_[0];

    # バッファリングせずに即時書き込み
    $w_io->printflush("write by printflush\n");
    print "- Please check the file size -\n";

    # 標準出力を読み込むハンドル
    my $r_io = IO::File->new;
    $r_io->fdopen(fileno(STDIN), "r");
    my $stdin = $r_io->getline;
    $r_io->close;
    chomp $stdin;

    # 書き込む前にバッファリングする(クローズするまで書き込まない)
    $w_io->print($stdin, " : buffering before write\n");
}

基本的な操作としては上記のことくらいができれば十分かなぁと思います。ファイルハンドルをオブジェクトとして扱えるのがいいですね。

注意が必要なのはバッファリングせずに即時書き込みを行うファイルをロックしている時のprintflushメソッドの挙動かなと思いました。

上記のスクリプトの実行結果のうち、該当部分だけを抜き出してみると、

[user 20070926]$ ./test_io_file.pl
- Please check the file size -
hskefhsekfhksjefhksehfs
[user 20070926]$
[user 20070926]$ tail test_6.txt
write by printflush
割り込みできてるよね?(printflush)
hskefhsekfhksjefhksehfs : buffering before write
割り込みできてないよね?(print)
[user 20070926]$

このようにprintflushメソッドによる書き込みは即時で行われるので、ファイルをロックしている状態であるにも関わらず、割り込みで書き込みが行われています。逆にprintメソッドによる書き込みはバッファリングされて、ロックが解除されたあとに行われています。

当たり前といえば当たり前の挙動なんですが、不用意にprintflushは使わない、ということでしょうか。