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

I'm be grateful for any criticism. This is pretty trivial code, so I'm not expecting much...

The only moderately interesting thing is that the original get_files() used File::Find and was about 25 percent wallclock seconds slower.

#!/usr/local/bin/perl require 5.6.0; use warnings; use strict; use File::Spec::Functions; my $gthumb_dir=catdir('..','go','pics','thumbs'); my $gHTMLPath='/go/pics/thumbs/'; ################################## # # # no user servicable parts below # # # ################################## # FILE: listthumbs.pl REVISION DATE: 09-12-2001 # # CGI to list display jpeg, gif & png files in a directory ##################### # Declarations # ##################### sub get_files($); # get a list of jpeg files; sub size_cmp(); # used in sort function compares two values sub main(); # ###################### # Run our program # ###################### main(); ###################### # Definitions # ###################### sub size_cmp(){ my @a_stat=stat($a) or die "couldn't stat\n $a \n$!\n"; my @b_stat=stat($b) or die "couldn't stat \n $b\n$!\n"; #7 is size so # sorting by size puts the duplicates next to each other #9 is modification time # sort reverse order return $b_stat[9] <=> $a_stat[9]; } sub get_files($){ my $myDir=shift; my @result_files; my @files; opendir(dirHandle,$myDir) || die "$! Couldn't open $myDir\n"; @files=readdir(dirHandle); foreach (@files){ if ($_=~m/\.((jpg)|(jpeg)|(gif)|(png))$/im){ push (@result_files,$_) ; } } closedir(dirHandle); return @result_files; } sub main(){ my @pics=get_files($gthumb_dir); @pics=map(catfile($gthumb_dir,$_),@pics); @pics=sort size_cmp @pics; for (my $i=0;$i<@pics;$i++){ $pics[$i]=~m/(\w*\.\w*$)/; $pics[$i]=$1; } print "content-type: text/html\n\n"; print "<!-- start code by $0 -->\n" ; my $cols=3; my $count=0; print '<TABLE>'; print '<TR>'; foreach (@pics){ $count++; --$cols; print "<TD width=200 align=left>\n"; print '<IMG SRC='. $gHTMLPath . $_ .'><BR>'."\n"; print ; print "</TD>\n"; if ($cols==0){ $cols=3; print "</TR>\n"; print '<TR>'; } } # end loop if ($count % 3!=0){print '</TR>';} print '</TABLE>'; print "there are $count thumbs<BR>\n"; print "<!-- end code by $0 -->\n" ; }
  • Comment on request criticism web page with images in dir (File::Find File::Spec)
  • Download Code

Replies are listed 'Best First'.
Re: request criticism web page with images in dir (File::Find File::Spec)
by broquaint (Abbot) on Sep 13, 2001 at 14:10 UTC
    This isn't exactly a critique but some suggestions of how you might do a couple of your functions -
    sub size_cmp($$) { return (stat($_[0]))[9] <=> (stat($_[1]))[9]; } sub get_files($) { return glob($_[0].'/*.{jpg,jpeg,gif,png}'); } sub main { $col=0; print "<table>\n<tr>\n"; @imgs = get_files($dir); for (@imgs) { print "\t<td width=\"200\">\n<img src="$Path/$_"></td>\n"; print "\n</tr>\n<tr>" if 0 == (3 % ++$col); } print "\n</tr>" if 0 != (3 % $col); print "</table>\nthere are ".@imgs." thumbs<br>\n"; }
    Basically I just removed a bunch of hoops you were going through to get fairly trivial information (glob() is your friend :o)
    Also, if you're doing HTML you may want to use here documents as they are enormously useful for making HTML in code readable. HTH

    broquaint

      I have been burnt by glob in the past. I can no longer recall what I did (wrong)?, but I wound up with filenames containing spaces split across seperate elements of the returned array.

      Older versions of person require spawning a child process to an external command (tcsh) in order to perform the glob. This may be a cost too high to bear.

      Truly, opendir/readdir/closedir are your friends ;).

      --
      g r i n d e r
      Thanks for your suggestions.

      I switched to file globbing. It seems simpler and is built into perls greater than 5.6.0

      I eliminated one of the map lines as the glob now returns the full path. I think this sped things up a bit

      I switched to mod ing by three as you suggested. % is probably 100 times more expensive than addition and eliminated but 1/100000 of a second isn't much more than a 1/1000 and the modulo is easier to read.

      I left the error checking in. --A few times it was handy to check to see that stat actually succeeded

      I left the sort in, I do want the most recent images first. I also suspect that the $a $b variables supplied by sort are quicker than $_[0] and $_1

      I left the printed comments and the print "content-type: text/html\n\n"; in as the former help me figure out problems when looking at HTML source and the later <large>:-></large> is needed for the HTML to display.

      #!/usr/local/bin/perl require 5.6.0; use warnings; use strict; use File::Spec::Functions; use File::Basename; my $gHTMLPath='/go/pics/thumbs/'; my $gthumb_dir=catdir('..','go','pics','thumbs'); ################################## # # # no user servicable parts below # # # ################################## if ($gthumb_dir=~m|/|){ $gthumb_dir.='/'; }elsif ($gthumb_dir=~m|\\|){ $gthumb_dir.='\\'; }elsif ($gthumb_dir=~m|:|){ $gthumb_dir.=':'; # we're on a Mac ??? not tested }else{ die "on unknown OS or couldn't get path at start \n" } # FILE: listthumbs.pl REVISION DATE: 09-13-2001 # # CGI to list display jpeg, gif & png files in a directory ##################### # Declarations # ##################### sub get_files($); # get a list of jpeg files; sub size_cmp(); # used in sort function compares two values sub main(); # ###################### # Run our program # ###################### main(); ###################### # Definitions # ###################### sub size_cmp(){ my @a_stat=stat($a) or die "couldn't stat\n $a \n$!\n"; my @b_stat=stat($b) or die "couldn't stat \n $b\n$!\n"; #7 is size so # sorting by size puts the duplicates next to each other #9 is modification time # sort reverse order return $b_stat[9] <=> $a_stat[9]; } sub get_files($) { my @result=glob("$_[0]*.{jpg,jpeg,png}"); if (0==@result) { die "couldn't glob in get_Files()"; } return @result; } sub main(){ my @pics=get_files($gthumb_dir); @pics=sort size_cmp @pics; for (my $i=0;$i<@pics;$i++){ $pics[$i]=basename($pics[$i]); } print "content-type: text/html\n\n"; print "<!-- start code by $0 -->\n" ; my $count=0; print '<TABLE>'; print '<TR>'; foreach (@pics){ $count++; print "<TD width=200 align=left>\n"; print '<IMG SRC='. $gHTMLPath . $_ .'><BR>'."\n"; print ; print "</TD>\n"; if (0==$count% 3){ print "</TR>\n"; print '<TR>'; } } # end loop print "\n</tr>" if 0 != (3 % $count); print '</TABLE>'; print "there are $count thumbs<BR>\n"; print "<!-- end code by $0 -->\n" ;


      --mandog
        Perhaps even -
        sub get_files { return sort { (stat($a))[9] <=> (stat($b))[9] } glob($_[0]."/*.{jpg,jpeg,png}") or die($_[0]." contained no images\n"); }
        And if you're worried about speed, then the modulo operator is probably the least of your worries, as pretty much all operations are going to be costly (but if you were really looking for speed, then you'd be using C ;o) This should eliminate a lot of unncessary operations ie saving an array into memory but only using one element, and having to enter the size_cmp function for every comparison.
        HTH

        broquaint