后备打开文件Perl

时间:2016-12-07 01:18:08

标签: perl scope

我正在尝试编写一个程序,其中perl打开一个文件,但如果该文件不存在或由于某种原因无法打开,则会回退到另一个文件。相关的一行是:

open(my $fh,"<","/path/to/file") or open (my $fh,"<","/path/to/alternate/file") or die

最终,我发现了:

open(my $fh,"<","/path/to/file") or open ($fh,"<","/path/to/alternate/file") or die

的工作。这两个陈述之间有什么区别,为什么不是第一个工作,第二个是正确的方法,还是有一些问题呢?

编辑:如果重要,我使用perl 5.12,第一个在"/path/to/file"存在的情况下失败。我倾向于,如果第一次打开成功,第二个open不应该运行,为什么$fh被第二个被覆盖?

2 个答案:

答案 0 :(得分:9)

我声明了一个变量。如果在相同的范围内使用两次相同的名称,稍后会提到它将是第二个,而不是第一个。您的代码将触发"my" variable ... masks earlier declaration in the same statement警告(如果您应该启用警告。)因此,如果第一次打开成功,它会设置一个稍后无法访问的$fh变量,并且第二个变量将保留处于未记录的未定义状态,因为它的声明实际上并未执行。 (请参阅perldoc perlsyn中的“这里是龙”警告,并意识到A or B相当于B unless A。)

你的“工作”代码也被打破了;虽然my返回新声明的变量,然后可以设置,但是词法的范围(后面提到它的变量找到变量)直到下面的语句才开始。所以你的第一个$fh是将在以后的行上访问的词法,但第二个实际上是一个全局变量(或者如果你使用严格的话,那么就是错误)。

正确的代码是:

my $fh;
open $fh, ... or open $fh, ...;

答案 1 :(得分:4)

其他人已经说过为什么现有代码不起作用,但也提供了具有竞争条件的版本:文件的状态可能会在您检查它和打开它之间发生变化。在你的情况下它是相当温和的,但它可以产生微妙的错误和安全漏洞。通常,您可以通过尝试打开文件来检查是否可以打开文件。

这是一种更通用的方法,可以扩展到多个文件,让您知道打开了哪个文件,并且不包含竞争条件。

use Carp;

sub try_open {
    my @files = @_;

    for my $file (@files) {
        if( open my $fh, "<", $file ) {
            return { fh => $fh, file => $file };
        }
    }

    croak "Can't open any of @files";
}