我想写一个名称在变量$filename
中的文件。
我不想覆盖它,所以我首先检查它是否存在,然后打开它:
#stage1
if(-e $filename)
{
print "file $filename exists, not overwriting\n";
exit 1;
}
#stage2
open(OUTFILE, ">", $filename) or die $!;
但这不是原子的。从理论上讲,有人可以在stage1
和stage2
之间创建此文件。是否有一些open
命令的变体会以原子方式执行这两个操作,因此如果文件存在,它将无法打开文件进行写入?
答案 0 :(得分:6)
以下是打开文件的原子方法:
#!/usr/bin/env perl
use strict;
use warnings qw(all);
use Fcntl qw(:DEFAULT :flock);
my $filename = 'test';
my $fh;
# this is "atomic open" part
unless (sysopen($fh, $filename, O_CREAT | O_EXCL | O_WRONLY)) {
print "file $filename exists, not overwriting\n";
exit 1;
}
# flock() isn't required for "atomic open" per se
# but useful in real world usage like log appending
flock($fh, LOCK_EX);
# use the handle as you wish
print $fh scalar localtime;
print $fh "\n";
# unlock & close
flock($fh, LOCK_UN);
close $fh;
调试会话:
stas@Stanislaws-MacBook-Pro:~/stackoverflow$ cat test
Wed Dec 19 12:10:37 2012
stas@Stanislaws-MacBook-Pro:~/stackoverflow$ perl sysopen.pl
file test exists, not overwriting
stas@Stanislaws-MacBook-Pro:~/stackoverflow$ cat test
Wed Dec 19 12:10:37 2012
答案 1 :(得分:4)
如果您担心修改同一文件的多个Perl脚本,只需使用每个脚本中的flock()函数来锁定您感兴趣的文件。
如果您担心可能无法控制的外部流程,可以使用sysopen()功能。根据 Programming Perl 一书(顺便说一下,我强烈推荐):
要解决此覆盖问题,您需要使用
sysopen
提供是否创建新文件的单独控制 破坏现有的。我们将放弃–e
文件存在测试 因为它在这里没有任何用处,只会增加我们的曝光率 竞争条件。
他们还提供了此示例代码块:
use Fcntl qw/O_WRONLY O_CREAT O_EXCL/;
open(FH, "<", $file)
|| sysopen(FH, $file, O_WRONLY | O_CREAT | O_EXCL)
|| die "can't create new file $file: $!";
在这个例子中,他们首先引入一些常量(用于sysopen
调用)。接下来,他们尝试使用open
打开文件,如果失败,则会尝试sysopen
。他们继续说:
现在即使文件以某种方式在打开之间存在 失败,当
sysopen
尝试打开新文件进行写作时,没有任何伤害 已完成,因为提供了标记,sysopen
将拒绝打开 已经存在的文件。
因此,为了清楚地了解您的情况,请完全删除文件测试(不再是第1阶段),仅使用类似于上面的代码的代码执行打开操作。问题解决了!