ファイルを開いてロックする

ファイルを開くときには、open(ファイル ハンドル, '<:encoding(文字コード)', "ファイル名") の形をよく使います。
読み書きするときに、指定した文字コードへの変換を自動的に行ってくれます。

ファイルをロックするときには、flock(ファイル ハンドル, 2) のようにします。
ファイル ハンドルで示される同じファイルに対してロックをかけると、それが解除されるまで次のロックをかけることができません。

これにより、同じファイルに同時に書き込もうとしてファイルが壊れる可能性を削減することができます。
……不運が重なると、壊れてしまうこともあります。

ファイルのロックは紳士協定のようなもので、ロックを気にせず操作しようと思えばできてしまいます。
つまり、うっかりロックのことを忘れたコードを書いてしまうと恐ろしいことにもなりかねません。

テスト環境

Windows XP Professional Service Pack 3
ActivePerl 5.8.8 Build 822
Encode-2.33

問題のあるサンプル コード

スクリプトは utf8 で保存してください。

#!/usr/local/bin/perl

use utf8;
use strict;
use Encode;

# 内容を確認するつもりでファイルを開く (shiftjis)
open(FHSJ, '<:encoding(shiftjis)', "./file_sjis.txt");
flock(FHSJH, 1);

# 上書きするつもりでファイルを開く (euc-jp)
open(FHEJ, '>:encoding(euc-jp)', "./file_euc-jp.txt");
flock(FHEJ, 2);

# 追記するつもりでファイルを開く (utf8)
open(FHU8, '>>:encoding(utf8)', "./file_utf8.txt");
flock(FHU8, 2);

# ファイル入出力
while (<FHSJ>) {
print FHEJ $_;
print FHU8 $_;
}

close(FHU8);
close(FHEJ);
close(FHSJ);

スクリプトを実行するたびに、shiftjis で書かれたファイル file_sjis.txt の内容が、file_euc-jp.txt (euc-jp) に上書きされ、また file_utf8.txt (utf8) に追記されます。

close(FHU8); の前に次のコードを足してやると、スクリプトが終了しなくなります。

# 同じファイルを開こうとする (euc-jp)
open(FHEJ2, '>:encoding(euc-jp)', "./file_euc-jp.txt");
flock(FHEJ2, 2);

これは、既にロックがかかっているファイルに対して、さらにロックをかけようとして、前のロックが外れるのを待ってしまうからです。

注意点

ファイルをオープンしてから、ロックをかけるまでの間は無防備になります。
したがって、別のプロセスが file_euc-jp.txt に対してロックをかけていたとしても、このスクリプトでファイルが開かれた瞬間に内容が破壊され、別のロックが解除されるのを待つのはそのあとになってしまいます。

詳しくは、各自で“perl open flock truncate”でググる などしてください。
flock の引数 '2' の意味も、気になったらすぐ調べてみましょう。

余談

ファイルを閉じるタイミングでロックも自動的に外れるはずなので、あまり気にしなくても良いらしいのですが、たまに気にしないといけない場合もあります。
心に留めておいてください。

インデントを再現すると面倒なことになりそうなので、今回はパス。


Powered by NIVOSIdE

今後 Google Analytics によるアクセス解析に記録を残さない