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

Aloha Monks,

Still rather new but plugging away. My question is about opening files in a loop. Before this in the same script I opened a file that sucessfully opens the file that delivers the $data_names. I changed filehandle names, I'm not sure why. Can you keep opening and closing files with the same file handle? I think I'm missing something really simple. Why won't this file open?

for ($i=0; $i < $lines1; $i++) { print "Name $i is $data_names[$i]<p\/>"; open(FH, "<Files/$data_names[$i].txt")or die "No can! :$!"; print "Name $i is $data_names[$i]<p\/>"; @data = <FH>; print "Data for $data_names[$i] is $data[$i]<p\/>"; close (FH); }

#!/usr/bin/perl -Tw ##################################### # Script by Joseph W. Guillaume # # Last updated June 2, 2005 # ##################################### use strict; use CGI qw(:standard); print "Content-Type: text/html\n\n"; print '<body bgcolor="cccccc">'; ##################################### my $employee=param('employee_name'); my $certification=param('certification'); my $month=param('month'); my @month=""; my $day=param('day'); my $year=param('year'); my $mo_yr=param('mo_yr'); my @data; my @data_names; my $data_names; my $data; my $lines; my $lines1; my $number; my $i; my @mon = qw (January Feburary March April May June July August Septem +ber October November December); ##################################### # Read Names.txt file # ##################################### open(JOE, "<Files/Names.txt") or die "No can! :$!"; @data_names = <JOE>; #foreach (@data_names) { #close (JOE); #} print "Names are @data_names<p\/>"; $lines1 =scalar@data_names; print "Number of records in Database is $lines1 <HR><p\/>"; ##################################### # Read File # ##################################### #print "Employee <b> $employee </b>"; for ($i=0; $i < $lines1; $i++) { print "Name $i is $data_names[$i]<p\/>"; open(FH, "<Files/$data_names[$i].txt")or die "No can! :$!"; print "Name $i is $data_names[$i]<p\/>"; @data = <FH>; print "Data for $data_names[$i] is $data[$i]<p\/>"; close (FH); } ##################################### # Checking File # ##################################### $lines=scalar@data/5; if ($lines <= 0) { #print "has no records at this time."; print "<p\/><hr><p\/>"; while ($lines >=1) { #for ($i=1; $i<=$lines; $i++) { $certification = shift(@data); print "Certification is $certification on "; my $number = shift (@data); $month = $mon [$number-1]; print "$month"; $day = shift (@data); print " $day,"; $year = shift(@data); print " $year"; $mo_yr = shift(@data); #print " $mo_yr"; print "<p\/><HR>"; $lines--; } } ##################################### print '<div align="center"><table width="120" border="1" cellspacing=" +2" cellpadding="0"><tr><td align="center">To go Back</td></tr><tr><td + align="center"><a href="http://www.hawaiicivilmarriage.com/FFD/index +.html">Click Here</a></td></tr></table><p></p></div>'; print '</body'; ##################################### #exit;
mahalo, joseph w. guillaume

Replies are listed 'Best First'.
Re: Opening files in a loop
by chromatic (Archbishop) on Jun 04, 2005 at 02:13 UTC
    @data = <FH>;

    The line of code I quoted overwrites the contents of @data each time through the loop. You can open as many files as you like, but the code only ever stores the lines from the last file you read.

    A quick fix might be to replace that with push @data, <FH>;.

    As a side note, you can loop over the contents of an array without an index with:

    for my $name (@data_names) { # open files here }
      Aloha,

      Yes your right. In fact how I have made progress was to reuse code, because reused code is proven. This was a time I strayed, (forgot I'm still a beginner). Thanks a lot for the help.

      Mahalo jwg

Re: Opening files in a loop
by Zaxo (Archbishop) on Jun 04, 2005 at 02:19 UTC

    Does chomping @data_names help?

    @data_names = <JOE>; chomp @data_names; # . . .
    Your file names probably don't have newlines at the end.

    Your loop could be written more perlishly as

    for (@data_names) { # $_ contains each name in turn }

    There is nothing wrong with re-using a file handle as you do. It's customary nowadays to use a lexical handle and 3-arg open,     open my $fh, '<', $_ or die $!;

    After Compline,
    Zaxo

Re: Opening files in a loop
by TedPride (Priest) on Jun 04, 2005 at 05:00 UTC
    To clarify, using a lexical file handle is as follows:
    my $handle; open ($handle, $filename); ... close ($handle);
    The advantage of lexicals is that you can use the same file handle (locally scoped) inside nested calls of a sub without collisions, and you can easily store the handle inside a data structure and retrieve it later.

    Re: Three arguments for open vs two - is this really a major concern if you control all file paths yourself? Seems to me that you only really need to worry if the path contains user input, in which case tainting / parsing should do the trick. Can you explain how someone could do damage by accident rather than on purpose?

      Sure, there are cases where two-argument open is mostly safe, but if you make a habit of using the three-argument form, you never have to consider whether the two-argument form is safe in any particular circumstance.

Re: Opening files in a loop
by graff (Chancellor) on Jun 04, 2005 at 16:09 UTC
    Either the code you posted is different in some details from the code you're running, or else the running code never actually produces any output that includes "Certification is ..."

    The problem would be easy to spot if you used proper indenting in your "if", "elsif", "else", "for" and "while" blocks. Here's how the last chunk of your code looks when properly indented (with some condensing and removal of unnecessary stuff to make it shorter):

    if ($lines <= 0) { #print "has no records at this time."; print "<p\/><hr><p\/>"; while ($lines >=1) { $certification = shift(@data); print "Certification is $certification on "; my $number = shift (@data); $month = $mon [$number-1]; $day = shift (@data); $year = shift(@data); $mo_yr = shift(@data); print "$month $day $year $mo_yr<p/><HR>"; $lines--; } }
    When the "if" and "while" blocks are bracketed that way, the condition for the "while" loop can never be met. Either remove the initial "if" statement there, or else move the "while" block outside the "if" block. In either case, look for a text editor that has a suitable mode for programming, and will do indentation for you (emacs and vi are the most popular examples, there are others).
      Aloha,

      Sorry it takes so long for me to respond. I appreciate and will endevor to try and follow the indention convention. Your code works (as mine did) but after a lot of study, yours makes more sense.

      Mahalo. JWG