Schnelle Liste von Dateien in Unterverzeichnissen
Theo
- perl
Hallo zusammen,
den Wunsch, eine Liste aller (oder bestimmter) Dateien in einem bestimmten Verzeichnis und aller Unterverzeichnisse zu erzeugen, findet man zu hunderten im Netz. Was dort empfohlen wird, sieht in etwa so aus:
use File::Find;
FileList("C:/test");
sub FileList {
my $RootPath = shift;
my @PDF = ();
find( sub { push @PDF, $File::Find::name if /.pdf$/ }, $RootPath);
print "$#PDF files\n";
return(@PDF);
};
Diese Routine benötigt in einem speziellen Fall (ca. 4000 Files in ca. 100 Unterverzeichnissen) ca. 40 Sekunden.
Das ist mir zu langsam.
Also habe ich eine etwas umständlichere Variante geschrieben (s.u.)
Diese Routine benötigt für das identische Verzeichnis ca. 8-10 Sekunden.
Mache ich da oben etwas falsch?
Vielleicht funktioniert die untere Variante nicht auf allen Systemen?
Kann mir das einer erklären...?
FileListFast("C:/test");
sub FileListFast {
my $RootPath = shift;
my @PDF = ();
my @DirList = ();
my @List = qx(dir "$RootPath" /-C /S); # execute, read directory
my $Directory = "";
my @FileList = ();
foreach (@List) {
if (/(\d\d.\d\d.\d\d\d\d)\s+(\d\d:\d\d)\s+(\d+)\s(.+).pdf$/) {
my ($Date, $Time, $Size, $Filename) = ($1, $2, $3, $4);
push(@PDF,$Directory.$Filename);
}
else {
if (/ Directory of (.+)\n/) {
$Directory = $1;
$Directory =~ s/\///g; # change backslash to foreslash
push(@DirList,$Directory);
};
};
};
print "$#PDF files in $#DirList directories\n";
return(@PDF);
};
Kann mir das einer erklären...?
Nur eine flüchtige Anmerkung: Perl ist nicht der schnellste Kandidat in Sachen Dateisystem gegenüber vergleichsweisen Programmen, die beispielsweise in C geschrieben sind. Zum Archivieren von Fotodateien hatte ich auch mal ein Perl-Script mit File::Find, einem Modul was an sich schon solche Scripts performant macht. Dieses Script hab ich vor einem Jahr als C-Programm geschrieben, es läuft um Größenordnungen schneller als der alte Kumpel in Perl.
Du verwendest qx(dir ...), das dürfte den Schub ausmachen, denn >dir< ist nicht einmal eine .exe sondern ein Systeminternes Kommando was im Kernel steckt und somit noch flotter ins Dateisystem greift. Der Sachverhalt wird klar, wenn Du eine Mütze voll Dateien mal mit dem Norton-Commander und einmal mit >copy< bewegst, >copy< ist wesentlich schneller (sone Frage hatte ich mal vor Jahren in der Hotline).
Natürlich ist qx(irgendwas) dann nicht mehr plattformunabhängig.
Viele Grüße,
Horst Haselhuhn
Moin Moin!
Du verwendest qx(dir ...), das dürfte den Schub ausmachen, denn >dir< ist nicht einmal eine .exe sondern ein Systeminternes Kommando was im Kernel steckt und somit noch flotter ins Dateisystem greift.
Das ist ja mal großer Quatsch. Unter DOS und Windows ist dir ein Buildin des Kommandointerpreters, sei es command.com oder cmd.exe. Unter Unixen aller Art ist es bestenfalls ein Alias für ls, und das ist ein Programm wie jedes andere. Im Kernel treibt sich das dir-Kommando auf keinen Fall rum.
Was die Performance angeht:
Natürlich ist ein in C geschriebenes Programm oft schneller als ein Perl-Script. Aber: Der Aufruf eines externen Programms ist relativ teuer, insbesondere wenn noch ein Kommandointerpreter im Spiel ist.
File::Find ist als eierlegende Wollmilchsau geschrieben, die find-Funktion hat aktuell elf verschiedene Optionen neben dem "wanted"-Callback, die u.a. filtern, sortieren, vor- und nacharbeiten und die Arbeitsreihenfolge ändern können. Natürlich ist so ein Monster nicht mehr unbedingt schnell.
Eine kleine while-Schleife mit einem todo-Array grast einen Dateibaum definitiv schneller als File::Find ab und spart den Child-Prozess ein.
Alexander
moin,
[..] Im Kernel treibt sich das dir-Kommando auf keinen Fall rum.
Zur Erinnerung:
Die 3 Dateien
command.com
io.sys
msdos.sys
bilden der Kernel von MS-DOS.
Viele Grüße,
Hotte
你好 hotti,
Zur Erinnerung:
Die 3 Dateien
command.com
io.sys
msdos.sysbilden der Kernel von MS-DOS.
Der Kernel von MS DOS ist die msdos.sys. Der Kernel vom Windows-DOS besteht aus der io.sys, die msdos.sys ist eine Konfigurations-Datei. Die command.com ist ausschließlich der Kommandozeilen-Interpreter und hat mit dem Kernel _nichts_ zu tun.
再见,
克里斯蒂安
Hallo,
ich nehme stark an, das liegt an den stat calls die find() durchführt.