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

Recently, I was working on a program that takes one input file and splits it into n other files depending on the content of each line. I figured the most efficient way to do this would be to keep all of my filehandles in a hash, so I wrote the following:

while (<>){ # do some stuff if (defined $fhs{$conn}){ local *FH = $fhs{$conn}; print FH $_; } else { local *FH; open(FH, '>', "conn-$conn") or die($!); print FH $_; $fhs{$conn} = \*FH{IO}; } }

I seem to be able to build up the file handles the way I expected, but by the time I get to the if block, the filehandle is closed. Is there a way I can keep it open? or is there a better way to do this?

Thanks!

Replies are listed 'Best First'.
Re: Storing open filehandles in a hash
by holli (Abbot) on Aug 16, 2006 at 14:21 UTC
    Avoid the globs and use IO::File instead. Then everything will work fine.
    while (<>){ # do some stuff unless defined ( $fhs{$conn} ) { $fhs{$conn} = IO::File->new(); die $! unless $fhs{$conn}->open(">conn-$conn"); } $fhs{$conn}->print ($_); }


    Update: added code


    holli, /regexed monk/
Re: Storing open filehandles in a hash
by ikegami (Patriarch) on Aug 16, 2006 at 14:37 UTC
    while (<>) { defined $fhs{$conn} or open($fhs{$conn}, '>', "conn-$conn") or die("Unable to create file conn-$conn: $!\n"); print { $fhs{$conn} } $_; }
      Can you shed some light on what the braces around $fhs{$conn} do in this case? It must have something to do with the file handle and print string being space separated, but I've been wondering for a while why we need those if we're using anything more complex than $variable_name but don't otherwise.

        See the last paragraph of print's documentation.

        To keep the parser sane, print is very limited as to what it can accept for the file handle argument. It accepts a scalar variable ($fh) or a bare word (FH), and that's probably it unless you wrap the expression in curlies. Inside the curlies can be any Perl expression, including the a hash lookup as desired by the OP.

        print { $fh } ...; print $fh ...; # Shorthand print { FH } ...; print FH ...; # Same thing, but also works under strict 'vars'. print { *FH } ...; print { $a[$i] } ...; print { $h{$k} } ...; print { $o->get_fh() } ...; print { $e ? *STDERR : *STDOUT } ...; etc.