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++;
}
}
open(FH, "<$fileName") or die "$! \n" if (<FILE_IS_NOT_ALREADY_OPEN>); # or something like close(FH) if (<FILE_IS_OPEN>); 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.
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.
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.
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With