Beefy Boxes and Bandwidth Generously Provided by pair Networks Frank
Just another Perl shrine

read directory

by Zcity (Novice)
on Jul 08, 2006 at 00:35 UTC ( #559887=perlquestion: print w/ replies, xml ) Need Help??
Zcity has asked for the wisdom of the Perl Monks concerning the following question:

How do you get the read directory function to sort by latest modified date???

Any advice? Thanks in advance.

use CGI ':standard'; use strict; use CGI::Carp qw/fatalsToBrowser/; use File::Spec::Functions; opendir( FILES, "pending" ) || die "Cannot opendir /some/path: $!"; print "Content-type: text/html\n\n"; print "<TABLE BORDER=1>\n<TR><TH align=left>Files</TH><TH align=left>Last Modified On</TH> </TR>"; my $files; my $mod; while ( $files = readdir(FILES) ) { $mod = ( stat( catfile( 'pending', $files ) ) )[9]; $mod = localtime($mod); # href will have path to new cgi print "<TR><TD><a href=createhtml.cgi?filename=" . $files . ">$files</a></TD><TD>$mod</TD> </TR>"; } print "</TABLE>"; closedir(FILES); sub Error { print "Content-type: text/html\n\n"; print "The server can't $_[0] the $_[1]: $! \n"; exit; }

Comment on read directory
Download Code
Re: read directory
by jbisbee (Pilgrim) on Jul 08, 2006 at 01:08 UTC
    Here is a quick example using glob, map, and sort to produce a list of files and their modified times. It's not quite a Swartzian transform, because we leave the modified time hanging around for the output.
    #!/usr/bin/perl use strict; use warnings; use CGI qw(:standard); my %cache = (); my @files = sort { $b->[1] <=> $a->[1] } map { [ $_, (stat($_))[9] ] } glob('pending/*'); print header; print "<table>\n"; for my $file (@files) { print "<tr><td>$file->[0]</td><td>" . localtime( $file->[1] ) . "</td></tr>\n"; } print "</table>\n";
    also in the future, put <code></code> around code you post :)


Re: read directory
by shmem (Canon) on Jul 08, 2006 at 10:49 UTC
    You don't. readdir (and glob) return the entries in the order the OS kernel pleases to present them. You have to sort yourself:
    @files = sort {-M $a <=> -M $b} <*>; # update - better without -M in sort opendir(D,$dir); @files = map { $_->[1] } sort { $a->[0] <=> $b->[0] } map { [-M $_, $_] } grep {!/^\.\.?$/} readdir(D);

    A related thread is here.


    update: added ST after reading TedPride's post ;-)

    _($_=" "x(1<<5)."?\n".q/)Oo.  G\        /
                                  /\_/(q    /
    ----------------------------  \__(m.====.(_("always off the crowd"))."
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      Update: Sorry, I know this post was a bit lame and didn't prove anything

      I just benchmarked the difference between "glob" and "<>" and found very little difference (subsequent runs flip-flopped which was faster). If that's the case, then I'd prefer the glob('pending/*') over the <pending/*> call because of the awkward bare word. But then, thats just me.

      #!/usr/bin/perl use strict; use warnings; use Benchmark qw(cmpthese); cmpthese( 20_000, { '<>' => sub { my @results = <pending/*>; }, 'glob' => sub { my @results = glob('pending/*'); }, }, );
      and the results
      Rate glob <> glob 7194/s -- -0% <> 7220/s 0% --


        well, <DATA> also has a bareword.. ;-)

        I'm not surprised that glob and <> down differ much, since they are essentially the same... bigger savings can be achieved by using -M instead of (stat)[9], because doing so eliminates the overhead of making a list just to get its 10th element.


        _($_=" "x(1<<5)."?\n".q/)Oo.  G\        /
                                      /\_/(q    /
        ----------------------------  \__(m.====.(_("always off the crowd"))."
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        I just benchmarked the difference between "glob" and "<>" and found very little difference

        That's hardly surprising since glob is the internal function implementing the "<*.c>" operator according to the documentation.

        David Serrano

Re: read directory
by TedPride (Priest) on Jul 08, 2006 at 20:07 UTC
    It might be more efficient to call ls, if the number of files in the directory is large. You certainly don't want to call -M from inside a sort, as shmem suggests.

    my @files = split /\n/, `ls -1t`; for (@files) { ... }
    The -1 modifier forces output to one column, and -t sorts by last time modified.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://559887]
Approved by prasadbabu
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (13)
As of 2014-04-23 20:23 GMT
Find Nodes?
    Voting Booth?

    April first is:

    Results (554 votes), past polls