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

Lets say I want to do some dynamic file handles
$fh[0] = "file1"; $fh[1] = "file2"; $fh[2] = "file3"; open($fh[0], "path/to/file/$fh[0]"); while(<$fh[0]>) { ... } close($fh[0]);
Is this possible in any form? Doing this, perl seems to get mad and crash & burn. If I do
while($fh[0]) { ... }
It tells me that I cannot use "file1" as a filehandle. Any suggestions?

Replies are listed 'Best First'.
Re: Dynamic File Handles
by trammell (Priest) on Jun 06, 2005 at 20:43 UTC
    From perldoc perlopentut:
    Indirect Filehandles
    
    "open"'s first argument can be a reference to a
    filehandle.  As of perl 5.6.0, if the argument is
    uninitialized, Perl will automatically create a
    filehandle and put a reference to it in the first
    argument, like so:
    
      open( my $in, $infile )
        or die "Couldn't read $infile: $!";
      while ( <$in> ) {
        # do something with $_
      }
      close $in;
    
    It doesn't get much more dynamic than that.
      Thats awesome. See If I just read the manual I would have been fine :-) Have a great day!
        Heh. For some reason I always assume that folks have read the fine manual before posting here. :)
Re: Dynamic File Handles
by jeffa (Bishop) on Jun 06, 2005 at 20:27 UTC

    The first argument to open is suppose to be filehandle, not the name of the file you want to open. Try this instead:

    use strict; use warnings; my @file = qw(foo bar baz); for (@file) { open FH, "path/to/file/$_"; print while <FH>; close FH; }

    UPDATE: Those aren't dynamic file handles, by the way. You are just storing the names of the files you want to open in an array, that's all.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      I understand that part. But what I need is the file handle to be dynamic Basically I want to beable to have a random set of files all open at the same time for a specific set of data mashing and mangling. So I want to beable to specify which files to have open, and the script opens them all at the same time
      @files =qw (file1 file2 file3 file4); foreach(@files) { open ($fh, "$_"); while(<$fh>) { ... } close($fh); }
      $fh will be a random string generated during each loop Yes, what I am doing is stupid. I know that much :-) But its for a dirty dirty piece of code. I dont want to have to keep opening and closing files. Thanks!

        Here's a subroutine that will return a hashref, where the keys are the filenames passed in (for those that it is able to open), and the values are filehandles.

        updated: removed extraneous "my $fh"

        sub open_files { my @files = @_; my %file_handles; for my $file ( @files ) { if ( open my $fh, '<', $file ) { $file_handles{ $file } = $fh; } else { warn "couldn't open $file for reading: $!\n"; } return \%file_handles; }
Re: Dynamic File Handles
by eyepopslikeamosquito (Archbishop) on Jun 06, 2005 at 20:56 UTC

    Not sure exactly what you are trying to achieve. However, it is easy to open multiple file handles at the same time. For example, you could use an array of file names and a "parallel" array of file handles, as shown in the example code below:

    use strict; use warnings; my @files = qw(file1 file2 file3); my @fh; foreach my $i (0..$#files) { open($fh[$i], $files[$i]) or die "open '$files[$i]': $!"; } foreach my $fh (@fh) { while(<$fh>) { print; } } foreach my $i (0..$#files) { close($fh[$i]) or die "close '$files[$i]': $!"; }

    Update: from perldoc -f open, "If FILEHANDLE is an undefined scalar variable (or array or hash element) the variable is assigned a reference to a new anonymous filehandle". In the open call in the example code above, I am using an undefined array element ($fh[$i]) to receive the new anonymous filehandle.

Re: Dynamic File Handles
by ivancho (Hermit) on Jun 07, 2005 at 02:08 UTC
    Of course it's possible - it wouldn't be Perl otherwise..

    You can even do funky stuff like: my @lines = map {<$_>} map {$fh[$_]} <>; though it's usually likely to shoot yourself in the foot in the process...

    Note that on some OSs there is a noticeable limit on the maximum number of files open - but no, 3 won't trigger it.. more like 255..
    it doesn't look like you want to write to some of those filehandles, but in case you do decide to, Perl will complain.. from
    perldoc -f print Note that if you're storing FILEHANDLES in an array or other expression, you will have to use a block returning its value instead: print { $files[$i] } "stuff\n"; print { $OK ? STDOUT : STDERR } "stuff\n";