Perl で安全にファイルを更新する

コードサンプル

my $path = “myfile.txt”; #最終的に保存したいファイル
my $contents = “…blabla…”; #保存する内容
my $temp = “${path}_”.time.’.temp’; #テンポラリファイル名
my $try = 4;
while (-f $temp && –$try){ #ファイル名重複チェック
sleep (1);
$temp = “${path}_”.time.’.temp’;
}
$try or die sprintf(
‘Failed to get a unique file name: %s’,
$temp,
);
#テンポラリファイルに書き出し
(open (FILE, “>$temp”)) or die sprintf(
‘OPEN ERROR: %s, %s’,
$temp,
$!
);
binmode FILE;
print FILE $contents;
(close (FILE)) or die sprintf(
‘CLOSE ERROR: %s, %s’,
$temp,
$!
);
#最後に置き換え
rename($temp, $path)
or die sprintf(
‘File replacement failed (%s, %s) : %s’,
$temp,
$path,
);

解説

更新のために上書きモード(「open (FILE, “>$path”)」)でファイルを開けてしまうとオープン時点でファイルに元々保存されていた内容がクリアされます。
書き出しの途中で何らかのエラーが起こった場合、処理前の内容がなくなってしまいますので、一時ファイルに保存まで成功した後にファイル名を変更します。

なお、テンポラリファイルのパス($temp)を最終保存したいパス($path)とは別のデバイスに指定してしまうと rename の際にエラーになります。