Как я могу открыть файл, только если он еще не открыт, в Perl? - PullRequest
5 голосов
/ 15 октября 2010

Если у меня есть подпрограмма, которая открывает файл, каков наилучший способ убедиться, что он открывает его только при первом вызове подпрограммы?У меня есть это, но не уверен, что его лучшая практика:

{
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++;
    }
}

Ответы [ 4 ]

8 голосов
/ 15 октября 2010

Звучит как хорошая причина использовать переменную состояния.Сохраните дескрипторы файлов в постоянном хеше.

#!/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 немного требователен к тому, что вы можете использовать в качестве аргумента дескриптора файла.

3 голосов
/ 16 октября 2010

Лучший способ - использовать Log :: Log4perl , чтобы вам не приходилось об этом думать и вы могли сосредоточиться на своей реальной задаче.

Помимо этого, вы можетеИспользуйте некоторые приемы для файлов и файловых дескрипторов, которые мы рассмотрим в Эффективное программирование на Perl .К счастью для вас, это также бесплатная глава , которую выдает наш издатель.

Короче говоря, вы не хотите думать об этом в своей процедуре регистрации.Это беспорядок.Вместо этого создайте метод, который либо возвращает кэшированный дескриптор файла, либо открывает его (это очень похоже на метод, который вы использовали бы для проверки связи с дескриптором базы данных и при необходимости переподключения):

 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;
     }
 }
0 голосов
/ 15 октября 2010

Я не думаю, что с использованием per se что-то не так, но если на самом деле нужно отслеживать только 1 файл, почему бы просто не оставить $log_fh в закрытии и использовать if(!$log_fh->opened()) вместо переменной count?

0 голосов
/ 15 октября 2010

Ну, для начала, $count++ должно идти внутри вашего оператора if и может быть изменено на $count=1. Вы также можете переименовать $ count в $file_opened_flag или что-то более значимое. Кроме этого, я не вижу в этом ничего плохого.

...