如何在 Perl 中仅打开尚未打开的文件?

发布于 2024-09-28 08:29:32 字数 412 浏览 7 评论 0原文

如果我有一个打开文件的子例程,确保它仅在第一次调用子例程时打开它的最佳方法是什么?我有这个,但不确定它是否是最佳实践:

{
my $count = 0;
sub log_msg {
    my ($msg,$name) = @_;

    if ($count == 0) {
        my $log_file_name = "/tmp/" . $name;
        open my $log_fh,">",$log_file_name or  croak "couldn't open $log_file_name : $!";
        print $log_fh "$timestamp: created and opened $log_file_name\n";
    }
    $count++;
    }
}

If I have a subroutine that opens a file what is the best way to ensure it opens it only upon the first time the subrountine is called? I have this but not sure if its best practice:

{
my $count = 0;
sub log_msg {
    my ($msg,$name) = @_;

    if ($count == 0) {
        my $log_file_name = "/tmp/" . $name;
        open my $log_fh,">",$log_file_name or  croak "couldn't open $log_file_name : $!";
        print $log_fh "$timestamp: created and opened $log_file_name\n";
    }
    $count++;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

荆棘i 2024-10-05 08:29:33

好吧,对于初学者来说,$count++ 应该放在 if 语句中,并且可以简单地更改为 $count=1。您可能还想将 $count 重命名为 $file_opened_flag 或更有意义的名称。除此之外,我认为这没有什么问题。

Well, for starters, the $count++ should go inside your if statement and can be changed to simply $count=1. You may also want to rename $count to $file_opened_flag or something more meaningful, as well. Other than that, I see nothing wrong with this.

幻想少年梦 2024-10-05 08:29:33

我不认为使用本身有什么问题,但如果真的只有 1 个文件要跟踪,为什么不将 $log_fh 保留在闭包中并使用 if(!$log_fh ->opened()) 而不是计数变量?

I don't think there is anything wrong with using per se but if there is really only 1 file to track, why not just keep $log_fh in the closure and use if(!$log_fh->opened()) instead of a count variable?

感情洁癖 2024-10-05 08:29:32

听起来像是使用状态变量的一个很好的理由。将文件句柄存储在持久哈希中。

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;

sub log_msg {
  state %fh;
  my ($msg, $name) = @_;

  unless ($fh{$name}) {
    warn "Opening $name\n";
    open $fh{$name}, '>', $name or die $!;
    print {$fh{$name}} scalar localtime, " Opened file\n";
  }

  print {$fh{$name}} $msg, "\n";
}

log_msg('Message1', 'first.log');
log_msg('Message2', 'first.log');
log_msg('MessageA', 'second.log');
log_msg('MessageB', 'second.log');

请注意打印调用中文件句柄周围的额外大括号。这是因为 print 对于可以用作其文件句柄参数的内容有点挑剔。

Sounds like a good reason to use a state variable. Store the filehandles in a persistent hash.

#!/usr/bin/perl

use 5.010;
use strict;
use warnings;

sub log_msg {
  state %fh;
  my ($msg, $name) = @_;

  unless ($fh{$name}) {
    warn "Opening $name\n";
    open $fh{$name}, '>', $name or die $!;
    print {$fh{$name}} scalar localtime, " Opened file\n";
  }

  print {$fh{$name}} $msg, "\n";
}

log_msg('Message1', 'first.log');
log_msg('Message2', 'first.log');
log_msg('MessageA', 'second.log');
log_msg('MessageB', 'second.log');

Note the extra set of braces around the filehandles in the print call. That's because print is a bit picky about what you can use as its filehandle argument.

囚我心虐我身 2024-10-05 08:29:32

最好的方法是使用 Log::Log4perl 这样你就不必考虑有了它,您就可以专注于真正的任务。

除此之外,您还可以使用我们在有效 Perl 编程中介绍的一些文件和文件句柄技巧。幸运的是,这也是我们的出版商赠送的免费章节

简而言之,您不想在日常日志记录中考虑这一点。这是混乱的代码。相反,创建一个返回缓存的文件句柄或打开它的方法(这很像您用来 ping 数据库句柄并在需要时重新连接的方法):

 sub log_msg {
      my( $self, $msg, $name ) = @_;

      print { $self->get_fh_by_name( $name ) } $msg;
      }

 BEGIN { # to define variables before the subroutine
 my %log_fhs;
 sub get_fh_by_name {
     my( $self, $name ) = @_;

     return $log_fhs{$name} if defined $log_fhs{$name};

     open my $log_fh, catdir( $base_dir, $name ) or croak "...";
     print $logfh ...

     $log_fhs{$name} = $log_fh;
     }
 }

The best way is to use Log::Log4perl so you don't have to think about it and you can focus on your real task.

Aside from that, you can use some of the tricks for files and filehandles that we cover in Effective Perl Programming. Luckily for you, that's also the free chapter that our publisher gives away.

In short, you don't want to think about that in your logging routine. It's cluttercode. Instead, create a method that either returns the cached filehandle or opens it (this is a lot like a method you'd use to ping a database handle and reconnect if needed):

 sub log_msg {
      my( $self, $msg, $name ) = @_;

      print { $self->get_fh_by_name( $name ) } $msg;
      }

 BEGIN { # to define variables before the subroutine
 my %log_fhs;
 sub get_fh_by_name {
     my( $self, $name ) = @_;

     return $log_fhs{$name} if defined $log_fhs{$name};

     open my $log_fh, catdir( $base_dir, $name ) or croak "...";
     print $logfh ...

     $log_fhs{$name} = $log_fh;
     }
 }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文