Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

How can you check to see if a file handle is already open?

by agent_smith (Scribe)
on Jan 16, 2008 at 16:00 UTC ( [id://662700]=perlquestion: print w/replies, xml ) Need Help??

agent_smith has asked for the wisdom of the Perl Monks concerning the following question:

Good Morning Esteemed Bretheren,

I have a question on checking to see if I have already opened a file handle, and if so just go ahead and write to it, don't try to re-create it.

I have a dataset that looks like:

12/01/2007 23:54:52;S;353958.admin2;user= .... 12/14/2007 23:54:52;S;354218.admin2;user= ....

I want to open files based on the date, write that line to that file, and not open unnecessary files for dates that do not exist. ie..
for ( 1...31) { open(FH$_, ">200712$_"), or die "Could not open $date $!\n"; }

I also don't want to be opening and closing file handles for every line.

Is it necessary to explicitly close all file handles as well?

Thanks in advance for your help and wisdom,

agent_smith

Replies are listed 'Best First'.
Re: How can you check to see if a file handle is already open?
by moritz (Cardinal) on Jan 16, 2008 at 16:05 UTC
    The best solution is to store them in an array:
    my @handles; for ( 1...31) { open(my $new_fh, ">200712$_"), or die "Could not open $date $!\n"; push @handes, $new_fh; }

    The file handles are closed automatically when they go out of scope (and no reference to them exists anymore), so you don't need to close them explictly.

    But it's good style to close them anyway, because if your function becomes part of a larger program the opened file handles my suck up resources.

      Thanks for the info, but doesn't this still open possibly unnecessary file handles? Maybe I should elaborate, and perhaps ask forgiveness for not being detailed enough.
      while(<DATA>) { chomp; if ($_ =~ m#^(\d+)/(\d+)/(\d+)\s+.*admin2;user) { open(FH$3, ">$3.$2.$1"); print "$_\n" FH$3; } }


      The problem with the above, is FH$3 may already be open, and I don't want to try to reopen it.

      And the problem with my first example is that it may open files for which I have no data, for example there was no data on the 15th, but I had opened the file anyway ( resulting in an un-needed 0 length file.

      Thanks again, for the help

      agent_smith
        I could have made it clearer ;-)

        You can actually avoid opening all the file handles with a small sub:

        my %handles; sub handle_for_name { my $f = shift; if ($handles{$f}){ return $handles{$f}; } else { open my $h, '<', $f or die "Can't open file '$f': $!"; $hanldes{$f} = $h; return $h; } }

        And then whenever you need a file handle you just call that function that opens the file if it's not already opened.

        You can make that sub even smaller with a neat little trick:

        use Memoize; memoize("handle_for_name"); sub handle_for_name { my $f = shift; open my $h, '<', $f or die "Can't open file '$f': $!"; return $h; }

        That's magic, eh?

        To answer your original question: if you have a file handle in a lexical variable $h, you can use if ($fh){ print "file opened\n"}

        moritz's approach is the same I had in mind, but there's something else that you should care about: if the dataset contains dates for different months and years, you could run out of resources quite easily (i.e. too many open files).

        In these cases, FileCache is your friend ;-)

        Why not just use the IO::Handle package?

        Use the opened method. It will tell you if a file handle is opened and ready.

        try the following code...

        use strict; use warnings; use IO::Handle; open my $fh, '>', 'file' or die $!; test_fh($fh); close $fh or die $!; test_fh($fh); sub test_fh { my ($fh) = @_; if ($fh->opened()) { print "fh is opened and ready\n"; } else { print "fh is closed\n"; } return; }
Re: How can you check to see if a file handle is already open?
by chaos_cat (Scribe) on Jan 16, 2008 at 16:28 UTC
    Good Morning agent_smith, I would address this problem by building a hash of file handles as I read through the data. The hash keys would be the dates, and the hash values would be the file handle (references). I might write it something like this: (warning, untried)
    my %file_handles = (); while (<>) { chomp; my @line = split /;/; if (not defined $file_handles{$line[0]} ){ open $file_handles{$line[0]}, ">$line[0].data"; } print $file_handles{$line[0]} join "\t", @line; }
    To close them, just loop through the hash and close each entry.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://662700]
Approved by wfsp
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-04-20 01:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found