2011-01-10 19 views
4

Ich versuche, die Liste der Dateien nach Änderungsdatum sortiert zu bekommen. Ich änderte das Beispielprogramm von Sort Directory and list files based on date and time und versuchte, es auszuführen.Abrufen der Liste der Dateien sortiert nach Änderungsdatum in Perl

sub get_sorted_files { 
    my $path = shift; 
    opendir my($dir), $path or die "can't opendir $path: $!"; 
    my %hash = map {$_ => (stat($_))[9]} 
       map { "$dir$_" } 
       grep { m/.*/i } 
       readdir $dir; 
    closedir $dir; 
    return %hash; 
} 

my %files = get_sorted_files("."); 
foreach my $keys (sort{$files{$a} <=> $files{$b}} keys %files) { 
    print "$keys\t", scalar localtime($files{$keys}), "\n"; 
} 

Ich verwende auf meinem Windows XP 32-Bit-Rechner mit Strawberry Perl Version 5.12.1.0.

Die Verzeichnisliste unter Windows ist:

alt text

Die Ausgabe lautet:

alt text

Der Ausgang nicht viel Sinn für mich macht. Was läuft falsch mit diesem Code und wie genau ist die foreach Schleife, die die Liste der Dateien sortiert?

Antwort

4

In get_sorted_files, $dir ist ein Glob, nicht der Verzeichnisname. Vielleicht meintest du $path?

my %hash = map {$_ => (stat($_))[9]} 
      map { "$path/$_" }    # $path, not $dir 
      grep { m/.*/i } 
      readdir $dir; 
+0

Danke Mob! Mein Schlechter konnte es früher nicht fangen! – rkg

7

Es gibt mindestens 2 Probleme mit diesem Code. Hier ist eine bessere Version:

use strict; 
use warnings; # I bet you weren't using this, because it produced a lot 

sub get_sorted_files { 
    my $path = shift; 
    opendir my($dir), $path or die "can't opendir $path: $!"; 
    my %hash = map {$_ => (stat($_))[9] || undef} # avoid empty list 
      map { "$path$_" } 
      readdir $dir; 
    closedir $dir; 
    return %hash; 
} 

my %files = get_sorted_files("./"); 
foreach my $key (sort{$files{$a} <=> $files{$b}} keys %files) { 
    print "$key\t", scalar localtime($files{$key}), "\n"; 
} 

Zuerst Sie $dir im ursprünglichen Code zu $path umbenannt, sie aber nicht in der map Linie ändern. Ihr $dir ist ein Verzeichnishandle; Von dort kommt der GLOB (0x ...).

Zweitens, alle Änderungsdaten lesen "Wed Dec 31 16:00:00 1969", weil Sie einen schlechten Pfadnamen an stat übergeben haben. (stat($_))[9] gab eine leere Liste zurück (weil Sie nach einer Datei wie GLOB(0x3f9b38)status.txt anstelle des korrekten Pfadnamens gesucht hatten) und so wurde der Hash tatsächlich mit Dateinamen als Schlüssel und Werten aufgefüllt. Der erste Dateiname war ein Schlüssel, der zweite war sein Wert, der dritte war der nächste Schlüssel und so weiter. localtime konvertiert den Dateinamen in eine Zahl (0) und konvertiert die Epochzeit 0 (1-Jan-1970 0:00:00 UTC) in Ihre Zeitzone.

Drittens erwartet $path mit einem Verzeichnistrennzeichen zu beenden, und Sie bestanden ".". Sie müssen "./" übergeben, oder noch besser, reparieren Sie es, so dass die Funktion bei Bedarf ein Trennzeichen anhängt.

Viertens, die grep hat nichts mehr getan und sollte entfernt werden. (Im ursprünglichen Code wurden nur bestimmte Dateinamen ausgewählt, aber das Muster wurde so geändert, dass es mit allem übereinstimmte.)

Zum Sortieren von Dateinamen: get_sorted_files gibt eine Liste mit Pfadnamen und Änderungszeiten zurück, die Sie in der Datei speichern %files Hash. keys %files gibt die Liste der Schlüssel (die Dateinamen) zurück und sortiert sie durch einen numerischen Vergleich des zugehörigen Wertes (der Änderungszeit).

+0

Danke ein Haufen CJM! Schlecht meinerseits, das nicht zu verstehen! Ich habe von deiner Antwort einiges gelernt. Danke noch einmal. – rkg

6

Verwenden Sie Perl 's sort Funktion. Es ist schneller und Sie bekommen, was Sie wollen, ohne den Hash.

Größe der Datei, dann Alter von Datei:

@s = sort {es $ a < => es $ b || -M $ b < => -M $ a} @a;

die oben wissen, können wir so etwas wie die unten sagen:

sub get_sorted_files { 
    my $path = shift; 
    opendir my($dirh), $path or die "can't opendir $path: $!"; 
    my @flist = sort { -M $a <=> -M $b } # Sort by modification time 
       map { "$path/$_" } # We need full paths for sorting 
       readdir $dirh; 
    closedir $dirh; 
    return @flist; 
} 
0

Für wirklich große Verzeichnisse, können Sie feststellen, dass Perl deutlich langsamer ist die nativen Tools, um die Sortierung zu tun, als mit. Zum Beispiel auf meiner Maschine, auf einem riesiges (341k-Dateien) Verzeichnis, nimmt dies etwa 1,5 Minuten:

my $mostrecent = `/bin/ls --full-time -lta $dir | head -1 2>/dev/null`; 

aber den Code in der Lösung oben (mit opendir und sort -M) dauert 30 bis 45 Sekunden länger. Es ist nicht nur wesentlich schneller, Sie können auch vermeiden, dass Perl das gesamte Array im Speicher ablegt, was für sich genommen ein Gewinn sein kann.

Beachten Sie, dass die oben auf einem ziemlich High-End-Blade-System Linux ist, so YMMV pro Computer/O ...

Verwandte Themen