Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I open a file only if it is not already open, in Perl?

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++;
    }
}
like image 733
ennuikiller Avatar asked Oct 15 '10 19:10

ennuikiller


People also ask

How do I know if a file is open in Perl?

open(FH, "<$fileName") or die "$! \n" if (<FILE_IS_NOT_ALREADY_OPEN>); # or something like close(FH) if (<FILE_IS_OPEN>); perl.

How do you create a file if not exist in Perl?

Write mode (>): If the file does not exist, a new file is created. If the file already exists, the content of the file is wipe out, therefore, you should use the write mode with extra cautious. Append mode ( >>): as its name implied, you can open the file for appending new content to the existing content of the file.

How do I open a file in Perl?

Following is the syntax to open file.open(DATA, "<file. txt"); Here DATA is the file handle, which will be used to read the file.


2 Answers

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.

like image 78
Dave Cross Avatar answered Sep 22 '22 23:09

Dave Cross


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;
     }
 }
like image 20
brian d foy Avatar answered Sep 22 '22 23:09

brian d foy