Home: Perl Programming Help: Intermediate:
Using variables for file handle



hacksics
Novice

Jan 20, 2009, 2:26 AM


Views: 4896
Using variables for file handle

Hi I want to use a variable for a filehandle. See the below code


Code
my $FH = "FILE"; 
open($FH, ">$file_name");


this works if use strict is not in used. Any suggestions?

Thanks!


hacksics
Novice

Jan 20, 2009, 2:53 AM


Views: 4895
Re: [hacksics] Using variables for file handle

By the way I found this helps,

Code
no strict 'refs';


But I'm not sure its the correct way!


FishMonger
Veteran / Moderator

Jan 20, 2009, 5:18 AM


Views: 4890
Re: [hacksics] Using variables for file handle

No, that's not how you want to do it.

Remove this line:
my $FH = "FILE";

and do this:
open my $FH, '>', $file_name or die "Can't open '$file_name' $!";


hacksics
Novice

Jan 20, 2009, 8:47 AM


Views: 4888
Re: [FishMonger] Using variables for file handle

Sorry, I dont quite understand. If I do that, how to assign a value to $FH, if it is declared when opening a file handle?

What I want is, assign a file handle name to variable and used it throughout the script. Suppose I want to have two file handles like this


Code
my $FH = ""; 
$FH = "FIRST_FILE";
open $FH, '>', $first_file_name;
# do something with the file

$FH = "SECOND_FILE";
open $FH, '>', $second_file_name;
# do something with the second file



FishMonger
Veteran / Moderator

Jan 20, 2009, 9:16 AM


Views: 4887
Re: [hacksics] Using variables for file handle

Before I explain why you shouldn't do it that way, can you explain why you want or feel the need to do it that way?


hacksics
Novice

Jan 20, 2009, 7:18 PM


Views: 4877
Re: [FishMonger] Using variables for file handle

I just wanted to write a module for log writing purposes. When I create a log writer objects, if I use the same file handle I guess it will be a problem if I write several log files in my program. Please find my module below


Code
package LogWriter; 

use strict;
no strict 'refs';

sub new
{
my($class) = $_[0];
my $self = {};

$self->{'FILE_NAME'} = $_[1];
my @arrTmp = split('/', $_[1]);
my($strFileHandleName) = split('\.', $arrTmp[$#arrTmp]);
$self->{'FILE_HANDLE'} = $strFileHandleName;

my $strDate = DateStr2();
$self->{'HEADING'} = "File name : $arrTmp[$#arrTmp]\n"
."Date Stamp: $strDate\n";
$self->{'DEBUG'} = "TRUE";
my @arrStack = ();
$self->{'STACK'} = \@arrStack;
$self->{'FUNC_CALL'} = {};
$self->{'FUNC_TAG'} = "00000";

bless($self, $class);
return $self;
}

sub LogHeading
{
my($self, $heading) = @_;
return $self->{'HEADING'} if (! $heading);

$self->{'HEADING'} = $heading;
return $heading;
}

sub LowLevelDebug
{
my($self, $debug) = @_;
return $self->{'DEBUG'} if (! $debug );

$self->{'DEBUG'} = $debug;
return $debug;
}

sub LogOpen
{
my($self) = @_;
my $Filename = $self->{'FILE_NAME'};
my $FileHandle = $self->{'FILE_HANDLE'};
chomp($FileHandle);

print "$Filename $FileHandle \n";

my $TimeNow = $self->DateStr2();

if (-e "$Filename")
{
`/usr/bin/mv $Filename $Filename.$TimeNow`;
}

if ( ! open($FileHandle, ">$Filename"))
{
print "\nERROR: Cannot open log file [$Filename]\n\n";
exit(1);
}

print $FileHandle $self->{'HEADING'};

}

sub DateStr2
{
my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $DateStr = sprintf("%04d_%02d_%02d_%02d_%02d_%02d", ($year + 1900), ($mon + 1), $mday, $hour, $min ,$sec);
return $DateStr;
}

sub Tabs
{
my($self) = @_;
my $count = scalar(@{$self->{'STACK'}});
for (my $i = 1; $i < $count; $i++)
{
print $self->{'FILE_HANDLE'} ("\t");
}
}

sub NewLogTag
{
my($self, $FunctionName) = @_;

my $FH = $self->{'FILE_HANDLE'};
my @CallStack = @{$self->{'STACK'}};
my %LogTagVal = %$self->{'FUNC_CALL'};

push(@CallStack, "$FunctionName");

$self->Tabs();
print $FH ("[FUNC:$FunctionName]\n");
$self->Tabs();
print $FH ("[CTACK:Global");

foreach my $func (@CallStack)
{
print $FH (" >> $func");
}

print $FH ("]\n");
$self->Tabs();
print $FH ("{\n");

if ( ! defined $LogTagVal{"$FunctionName"})
{
$LogTagVal{"$FunctionName"} = 1;
}
else
{
$LogTagVal{"$FunctionName"} ++;
}

my $tempval = $LogTagVal{"$FunctionName"};
$self->{'FUNC_TAG'} = sprintf("FUNCALLNO:%04d", $tempval);
}

sub EndLogTag
{
my($self) = @_;
my $FH = $self->{'FILE_HANDLE'};
my @CallStack = @{$self->{'STACK'}};

$self->Tabs();
print $FH ("}\n");
pop(@CallStack);
}

sub Log
{
my($self, $text, $line) = @_;
my $FH = $self->{'FILE_HANDLE'};

chomp($text);
print $FH ("~|$line|$text\n");
}

sub LogText
{
my($self, $text, $line) = @_;
my $LogTag = $self->{'FUNC_TAG'};
my $FH = $self->{'FILE_HANDLE'};

my $TimeNow = $self->DateStr2();
$self->Tabs();
print $FH ("\t~$TimeNow [TEXT]|$LogTag|LINE:$line|$text\n");
}

sub LogWarn
{
my($self, $text, $line) = @_;
my $LogTag = $self->{'FUNC_TAG'};
my $FH = $self->{'FILE_HANDLE'};

my $TimeNow = $self->DateStr2();
$self->Tabs();
print $FH ("\t~$TimeNow [WARN]|$LogTag|LINE:$line|$text\n");
}

sub LogInfo
{
my($self, $text, $line) = @_;
my $LogTag = $self->{'FUNC_TAG'};
my $FH = $self->{'FILE_HANDLE'};

if($self->{'DEBUG'} eq "TRUE")
{
my $TimeNow = $self->DateStr2();
$self->Tabs();
print $FH ("\t~$TimeNow [INFO]|$LogTag|LINE:$line|$text\n");
}
}

sub LogError
{
my($self, $text, $line) = @_;
my $LogTag = $self->{'FUNC_TAG'};
my $FH = $self->{'FILE_HANDLE'};

my $TimeNow = $self->DateStr2();
$self->Tabs();
print $FH ("\t~$TimeNow [EROR]|$LogTag|LINE:$line|$text\n");
}

sub LogClose
{
my($self) = @_;
my $FH = $self->{'FILE_HANDLE'};
close($FH);
}



FishMonger
Veteran / Moderator

Jan 21, 2009, 6:12 AM


Views: 4861
Re: [hacksics] Using variables for file handle

Unless this is simply an academic exercise, I'd highly recommend using the proven and well written Log::Log4perl instead of what you currently have written.
http://search.cpan.org/~mschilli/Log-Log4perl-1.20/lib/Log/Log4perl.pm


hacksics
Novice

Jan 21, 2009, 5:51 PM


Views: 4854
Re: [FishMonger] Using variables for file handle

Thank you :)

But are there any alternatives available to overcome the "strict ref" error while using variables as file handle?


FishMonger
Veteran / Moderator

Jan 21, 2009, 6:08 PM


Views: 4852
Re: [hacksics] Using variables for file handle

Simple, don't assign a value to the var.

To conform to the restrictions of the strict pragma, variables used for filehandles need to be undefined when the filehandle is created. If the variable is defined with the my keyword, as it should be, the filehandle will automatically be closed when it goes out of scope.


FishMonger
Veteran / Moderator

Jan 21, 2009, 6:50 PM


Views: 4851
Re: [hacksics] Using variables for file handle

On a side note regarding your code, there are a couple issues you should be aware of.

This bit has 3 issues.

Code
if (-e "$Filename")  
{
`/usr/bin/mv $Filename $Filename.$TimeNow`;
}


You can learn about the first 2 issues by reading these FAQ.
perldoc -q quoting
perldoc -q "What's wrong with using backticks in a void context?"

Why use backticks to spawn a new process and make the script non portable when Perl has methods to rename the file in a portable manor?

The DateStr2 sub could be reduced and simplified by using the strftime function in the POSIX module.


hacksics
Novice

Jan 21, 2009, 11:02 PM


Views: 4847
Re: [FishMonger] Using variables for file handle


In Reply To
Simple, don't assign a value to the var.

To conform to the restrictions of the strict pragma, variables used for filehandles need to be undefined when the filehandle is created. If the variable is defined with the my keyword, as it should be, the filehandle will automatically be closed when it goes out of scope.


Thanks a million.

But If I define the FH as you explained I wont be able to access that FH from other sub routine right?


FishMonger
Veteran / Moderator

Jan 22, 2009, 5:23 AM


Views: 4838
Re: [hacksics] Using variables for file handle


In Reply To
But If I define the FH as you explained I wont be able to access that FH from other sub routine right?


What makes you think that?

You access it via the hash key, not the value of that key, which is what you're doing.

Here's a simple example.

Code
use strict; 
use warnings;

my $logfile = create_filehandle('/path/to/file.log');
writelog($logfile, 'this is a test messege');

sub create_filehandle {
my $FH = {};
open $FH->{filehandle}, '>>', $_[0] or die "can't open '$_[0]' $!";
return $FH;
}

sub writelog {
print { $_[0]->{filehandle} } "$_[1]\n";
}



hacksics
Novice

Jan 22, 2009, 7:47 AM


Views: 4835
Re: [FishMonger] Using variables for file handle

Thanks, Got the point :)