[gelöst] Rekursive Verzeichnis-Suche unter Linux (und Co)

Für Fragen von Einsteigern und Programmieranfängern...
Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 988
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Linux Mint 20 , FPC 3.3.1 , Lazarus 2.1.0 -Win10 & XE7Pro
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

[gelöst] Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von kralle »

Moin,

für eine kleine nervige Aufgabe dachte ich mir:" Schreibst Du Dir schnell mal ein kleines Tool.". Aber , ....

Eigentlich schon x-mal eingesetzt, wollte ich unter Linux (Mint 19.1) nur ein Verzeichnis rekursiv durchsuchen und hinterher die gefundenen Dateien umbenennen.

Nur es kommt nichts in der Ergebnisliste an.
Wenn ich schon dabei bin, ist es aufwendig die Suche Plattformunabhängig zu gestalten?

Code: Alles auswählen

 
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;  //Rekursive Suche
    CheckBox2: TCheckBox; // Altes Ergebnis löschen
    LabeledEdit1: TLabeledEdit;
    ListBox1: TListBox;
    SelectDirectoryDialog1: TSelectDirectoryDialog;
    procedure Button1Click(Sender: TObject);
  private
 
  public
 
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.lfm}
 
procedure GetFilesInDirectory(Directory: string; const Mask: string;
                              List: TStrings;
                              WithSubDirs, ClearList: Boolean);
 
// Quelle:
// https://www.delphi-treff.de/tipps-trick ... en-suchen/
//
// Für Linux: Pfadtrennzeichen "umgedreht" bzw. gelöscht
//
  procedure ScanDir(const Directory: string);
  var
    SR: TSearchRec;
  begin
    if FindFirst(Directory + Mask, faAnyFile and not faDirectory, SR) = 0 then try
      repeat
        List.Add(Directory + SR.Name)
      until FindNext(SR) <> 0;
    finally
      FindClose(SR);
    end;
 
    if WithSubDirs then begin
      if FindFirst(Directory + '*.*', faAnyFile, SR) = 0 then try
        repeat
          if ((SR.attr and faDirectory) = faDirectory) and
             (SR.Name <> '.') and (SR.Name <> '..') then
            ScanDir(Directory + SR.Name ); // + '\');
        until FindNext(SR) <> 0;
      finally
        FindClose(SR);
      end;
    end;
  end;
 
begin
  List.BeginUpdate;
  try
    if ClearList then
      List.Clear;
    if Directory = '/' then Exit;
    if Directory[Length(Directory)] <> '/' then
      Directory := Directory + '/';
    ScanDir(Directory);
  finally
    List.EndUpdate;
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
Mask : String;
 
begin
  If  LabeledEdit1.text='' then LabeledEdit1.text:='*.*';
  if SelectDirectoryDialog1.Execute then
  GetFilesInDirectory(SelectDirectoryDialog1.FileName, Mask, Listbox1.Items, CheckBox1.checked, CheckBox2.checked);
end;
 
end.
 
 


Man merkt ich habe einfach zu wenig Zeit fürs Programmieren.

Gruß HEiko
Zuletzt geändert von kralle am Mo 22. Jul 2019, 16:15, insgesamt 1-mal geändert.
OS: Manjaro Linux, Debian und Windows 10
FPC-Version: 3.2.2 , Lazarus 3.0
+ Delphi XE7SP1

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6198
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von af0815 »

Da gibt es eine Plattformkonstante für den Verzeichnisseperator.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von Ally »

Hallo kralle,

ich benutze das hier unter Windows, schau doch mal ob es auch unter Linux funktioniert. Feedback würde mich freuen. :D

Gruß Roland

Code: Alles auswählen

unit rhsDateisuche;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, Forms, Dialogs, LazUTF8;
 
procedure Dateisuche(StartPfad, DateiErw: String; DListe: TStrings; UnterOrdner: Boolean; var Abbrechen: Boolean);
 
 
implementation
 
//------------------------------------------------------------------------------
// Eine Dateierweiterung muss immer mit einem Semikolon abgeschlossen werden.
// Wenn nach mehreren Erweiterungen gleichzeitig gesucht werden soll muss
// jede Einzelne mit einem Semikolon abgeschlossen werden (auch die Letzte).
// Beisp.: Durchsuche(StartPfad, '*.BMP;*.JPG;*.PNG;' Dateiliste);
//------------------------------------------------------------------------------
procedure Dateisuche(StartPfad, DateiErw: String; DListe: TStrings; UnterOrdner: Boolean; var Abbrechen: Boolean);
 
  procedure SearchTree;
  var
    SearchRec: TSearchRec;
    Ende: Integer;
    Pfad: String;
    Erweiter: String;
  begin
    DateiErw := UTF8LowerCase(DateiErw);
    Pfad := IncludeTrailingPathDelimiter(GetCurrentDir);
    Ende := FindFirst('*.*', 0, SearchRec);
    while Ende = 0 do
    begin
      try
        begin
          Erweiter := UTF8LowerCase(ExtractFileExt(SearchRec.Name) + ';');
          Application.ProcessMessages;
          if Abbrechen then
            Abort;
          if (UTF8Pos(Erweiter, DateiErw) > 0) and (UTF8Length(Erweiter) > 1) then
            DListe.Add(Pfad + SearchRec.Name);
        end
      except
        on EOutOfResources do
        begin
          ShowMessage('Zu viele Dateien.');
          Abort;
        end;
      end;
      Ende := FindNext(SearchRec);
    end;
    {Now that we have all the files we need, lets go to a subdirectory.}
    if UnterOrdner then
    begin
      Ende := FindFirst('*.*', faDirectory, SearchRec);
      while Ende = 0 do
      begin
        {If there is one, go there and search.}
        if ((SearchRec.attr and faDirectory = faDirectory) and (SearchRec.Name <> '.') and (SearchRec.Name <> '..')) then
        begin
          SetCurrentDir(SearchRec.Name);
          SearchTree; {Time for the recursion!}
          SetCurrentDir('..'); {Down one level.}
        end;
        Ende := FindNext(SearchRec); {Look for another subdirectory}
      end;
    end;
  end; {SearchTree}
 
begin
  DListe.Clear;
  SetCurrentDir(StartPfad);
  SearchTree;
end;
 
end.

Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 988
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Linux Mint 20 , FPC 3.3.1 , Lazarus 2.1.0 -Win10 & XE7Pro
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von kralle »

Moin,

af0815 hat geschrieben:Da gibt es eine Plattformkonstante für den Verzeichnisseperator.

Das mit

Code: Alles auswählen

DirectorySeparator
war schon mal der Schubs in die richtige Richtung.
Jetzt, laden die Dateinamen in der Listbox.
Schnell noch der Listbox ein

Code: Alles auswählen

 ListBox1.Sorted:= True
verpasst und die Dateien sind schon mal vorsortiert und nicht mehr in der Reihenfolge wie sie auf der Platte liegen.

Danke.

Der nächste Schritt ist dann das Umbenennen der Dateien.
Da geht das dann wieder los mit den ganzen Möglichkeiten, weshalb das nicht funktionieren kann und den erzeugen der entsprechenden Meldungen.
(Daten lagen auf einem Stick und der wurde gezogen, es war nur Leseberechtigung vorhanden, Datenträger ist voll, Datei ist schon vorhanden, usw.)

Gruß HEiko
OS: Manjaro Linux, Debian und Windows 10
FPC-Version: 3.2.2 , Lazarus 3.0
+ Delphi XE7SP1

Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 988
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Linux Mint 20 , FPC 3.3.1 , Lazarus 2.1.0 -Win10 & XE7Pro
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von kralle »

Moin,

jetzt ist nur die Frage: ist der

Code: Alles auswählen

DirectorySeparator
das einzige was ich beachten musste, um Plattform unabhängig zu werden?
Ich wollte mir jetzt einmal diese Procedure so fertig machen, dass ich sie platformunabhängig immer wieder nutzen kann.

Wenn ich mir aber das hier https://wiki.lazarus.freepascal.org/Multiplatform_Programming_Guide durchlese, dann ist das definitiv nicht einfach und wahrscheinlich an einigen Stellen ohne "Betriebssystem-Weiche" nicht realisierbar.
Oder sehe ich das falsch?

Gruß Heiko
OS: Manjaro Linux, Debian und Windows 10
FPC-Version: 3.2.2 , Lazarus 3.0
+ Delphi XE7SP1

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von wp_xyz »

kralle hat geschrieben:wollte ich unter Linux (Mint 19.1) nur ein Verzeichnis rekursiv durchsuchen und hinterher die gefundenen Dateien umbenennen.

Für's Durchsuchen gibt es in der Unit "FileUtil" auch die Routine FindAllFiles, die die gefundenen Dateinamen in einer StringListe ablegt.

Code: Alles auswählen

function FindAllFiles(const SearchPath: String; SearchMask: String = '';
  SearchSubDirs: Boolean = True; DirAttr: Word = faDirectory;
  MaskSeparator: char = ';'; PathSeparator: char = ';'): TStringList; overload;
 
procedure FindAllFiles(AList: TStrings; const SearchPath: String;
  SearchMask: String = ''; SearchSubDirs: Boolean = True; DirAttr: Word = faDirectory;
  MaskSeparator: char = ';'; PathSeparator: char = ';'); overload;

Die Routine verwendet intern den TFileSearcher, dessen Ereignis OnFileFound du verwenden kannst, um die gefundenen Dateien gleich umzubenennen.

Code: Alles auswählen

type
  TFileIterator = class
    [...]
  public
    procedure Stop;
    function IsDirectory: Boolean;
  public
    property FileName: String read GetFileName;
    property FileInfo: TSearchRec read FFileInfo;
    property Level: Integer read FLevel;
    property Path: String read FPath;
    property Searching: Boolean read FSearching;
  end;
 
  TFileFoundEvent = procedure (FileIterator: TFileIterator) of object;
  TDirectoryFoundEvent = procedure (FileIterator: TFileIterator) of object;
  TDirectoryEnterEvent = procedure (FileIterator: TFileIterator) of object;
 
  TFileSearcher = class(TFileIterator)
    [...]
  public
    constructor Create;
    procedure Search(ASearchPath: String; ASearchMask: String = '';
      ASearchSubDirs: Boolean = True; CaseSensitive: Boolean = False);
  public
    property MaskSeparator: char read FMaskSeparator write FMaskSeparator;
    property PathSeparator: char read FPathSeparator write FPathSeparator;
    property FollowSymLink: Boolean read FFollowSymLink write FFollowSymLink;
    property FileAttribute: Word read FFileAttribute write FFileAttribute default faAnyfile;
    property DirectoryAttribute: Word read FDirectoryAttribute write FDirectoryAttribute default faDirectory;
    property OnDirectoryFound: TDirectoryFoundEvent read FOnDirectoryFound write FOnDirectoryFound;
    property OnFileFound: TFileFoundEvent read FOnFileFound write FOnFileFound;
    property OnDirectoryEnter: TDirectoryEnterEvent read FOnDirectoryEnter write FOnDirectoryEnter;
  end;

Benutzeravatar
kralle
Lazarusforum e. V.
Beiträge: 988
Registriert: Mi 17. Mär 2010, 14:50
OS, Lazarus, FPC: Linux Mint 20 , FPC 3.3.1 , Lazarus 2.1.0 -Win10 & XE7Pro
CPU-Target: 64Bit
Wohnort: Bremerhaven
Kontaktdaten:

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von kralle »

Moin,
wp_xyz hat geschrieben:Für's Durchsuchen gibt es in der Unit "FileUtil" auch die Routine FindAllFiles, die die gefundenen Dateinamen in einer StringListe ablegt.

Und die Routine ist von Haus aus Plattformunabhängig?

Gruß HEiko
OS: Manjaro Linux, Debian und Windows 10
FPC-Version: 3.2.2 , Lazarus 3.0
+ Delphi XE7SP1

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von wp_xyz »

kralle hat geschrieben:Moin,
wp_xyz hat geschrieben:Für's Durchsuchen gibt es in der Unit "FileUtil" auch die Routine FindAllFiles, die die gefundenen Dateinamen in einer StringListe ablegt.

Und die Routine ist von Haus aus Plattformunabhängig?

Natürlich

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von Ally »

Hallo wp_xyz,

FindAllFiles kannte ich noch nicht. Ich habe das gerade mal ausprobiert, funktioniert, ist aber um den Faktor 2-3 langsamer als meine selbst "zusammengestrickte" Routine. :?:
Gerade bei etwas tieferen Verzeichnisstrukturen merkt man das ganz deutlich.

Ich verwende das so, oder mache ich da was falsch?

Code: Alles auswählen

 
Dateiliste := FindAllFiles(direditQuelle.Text, '*.3gp;*.gpx;*.jpeg;*.jpg;*.mov;*.mp4;*.mpeg;*.mpg;*.mts;', true);

Gruß Roland

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von Warf »

Ally hat geschrieben:FindAllFiles kannte ich noch nicht. Ich habe das gerade mal ausprobiert, funktioniert, ist aber um den Faktor 2-3 langsamer als meine selbst "zusammengestrickte" Routine. :?:
Gerade bei etwas tieferen Verzeichnisstrukturen merkt man das ganz deutlich.


Ziemlich simpel, du rufst rekursiv nur SearchTree auf, was keine argumente entgegen nimmt, FindAllFiles ruft rekursiv procedure DoSearch(const APath: String; const ALevel: Integer); auf, was einen String Pointer (der eventuell später kopiert werden muss wegen lazy copy und so) und einen Integer auf den Stack pushen muss.

Zu deiner eigenen lösung, die verändert das Working directory via SetCurrentDirectory, ohne es am ende korrekt wiederherzustellen, dieses Verhalten ist komplett inakzeptabel und würde niemals so in meine Codebasis kommen

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von Ally »

Hallo Warf,
Ziemlich simpel, du rufst rekursiv nur SearchTree auf, was keine argumente entgegen nimmt, FindAllFiles ruft rekursiv procedure DoSearch(const APath: String; const ALevel: Integer); auf, was einen String Pointer (der eventuell später kopiert werden muss wegen lazy copy und so) und einen Integer auf den Stack pushen muss.
Ok. aber was ist daran falsch? (schneller ist es ja mal)

Zu deiner eigenen lösung, die verändert das Working directory via SetCurrentDirectory, ohne es am ende korrekt wiederherzustellen, dieses Verhalten ist komplett inakzeptabel und würde niemals so in meine Codebasis kommen
Stimmt. Da das bei mir hier gerade keine Rolle spielt, ist mir das noch gar nicht aufgefallen. :oops:

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von Warf »

Ally hat geschrieben:Ok. aber was ist daran falsch? (schneller ist es ja mal)


Daran ist nichts falsch, du machst aber auch strikt was anderes, der Searcher der von FindAllFiles verwendet wird weiß zu jedem zeitpunkt wie tief er ist, dafür muss diese Info mitgegeben werden (Du brauchst das nicht also hast du diese Info auch nicht). Ich glaub aber der größte geschwindigkeitsvorteil kommt daher das du das WorkingDirectory abused und damit die lazy copy mechanik von Pascal Strings umgehst (da das dann vom OS gehandled wird, und das C strings verwendet). Mehr ein hack als ein feature, da das OS natürlich auch viel langsamer sein könnte (bzw. damit bist du performancetechnisch halt ziemlich OS abbhängig).

Aber wenn dir performance wirklich wert ist, besonders bei sehr tiefen ordnerstrukturen, dann benutz keine Rekursive Methode in ersterlinie, sondern nen iterativen ansatz (mit nem stack um den state zu speichern) Beispiel:

Code: Alles auswählen

procedure findAllFilesIter(BasePath: String; Mask: String; Output: TStrings);
var
  Stack: TStringList;
  searchPath: String;
  sr: TSearchRec;
begin
  Stack:= TStringList.create();   
  try
    Stack.Add(BasePath);
    while Stack.Count>0 do
    begin
      searchPath := Stack[Stack.Count-1];
      Stack.Delete(Stack.Count-1);
      searchPath := IncludeTrailingPathDelimiter(searchPath);
      if FindFirst(searchPath + Mask, faAnyFile - faDirectory, sr) = 0 then
      try
        repeat
          Output.Add(searchPath + sr.Name);
        until FindNext(sr) <> 0;
      finally
        FindClose(sr);
      end;
      if FindFirst(searchPath + '*', faDirectory, sr) = 0 then
      try
        repeat
          if (sr.Name <> '.') and (sr.Name <> '..') then
            Stack.Add(searchPath + sr.Name);
        until FindNext(sr) <> 0;
      finally
        FindClose(sr);
      end;
    end;
  finally
    Stack.Free;
  end;
end;


PS: was wahrscheinlich auch relevant sein sollte, FindAllFiles kommt nicht mit dem Unix "~" Pfad (also home directory) klar.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von wp_xyz »

Ally hat geschrieben:Hallo wp_xyz,

FindAllFiles kannte ich noch nicht. Ich habe das gerade mal ausprobiert, funktioniert, ist aber um den Faktor 2-3 langsamer als meine selbst "zusammengestrickte" Routine. :?:
Gerade bei etwas tieferen Verzeichnisstrukturen merkt man das ganz deutlich.

Ich verwende das so, oder mache ich da was falsch?

Code: Alles auswählen

 
Dateiliste := FindAllFiles(direditQuelle.Text, '*.3gp;*.gpx;*.jpeg;*.jpg;*.mov;*.mp4;*.mpeg;*.mpg;*.mts;', true);

Gruß Roland

Nein, das ist schon in Ordnung. Warum ich trotz der bereits gegebenen Antworten anderer User hier noch meinen Senf dazugebe, ist, dass du von den beiden Varianten von FindAllFiles die Funktion verwendest. Das ist nicht falsch, nur muss man sich der Konsequenzen bewusst sein, wenn man einen Aufruf wie den folgenden macht, der syntaktisch richtig ist, aber ein Speicherleck erzeugt:

Code: Alles auswählen

  ListBox1.Items := FindAllFiles(....);

Denn die Funktion FindAllFiles erzeugt eine StringListe, die bei der Zuweisung an ListBox1.items in die Items der Listbox kopiert wird, und anschließend weiterexistiert, weil man keine Variable dafür hat um sie wieder zu zerstören. Daher verwende ich viel lieber die Prozedur-Variante von FindAllFiles, bei der die StringListe bereits vor dem Aufruf von FindAllFiles existieren muss, so dass man sie auch problemlos wieder entfernen kann. Kostet hat etwas mehr Tipp-Arbeit:

Code: Alles auswählen

var
  L: TStrings;
begin
  L := TStringList.Create;
  try
    FindAllFiles(L, ....);
    Listbox1.Items := L;
  finally
    L.Free;
  end;

Wenn man das weiß, geht es natürlich auch mit der Funktion, nur ist beim flüchtigen Überfliegen des Quelltexts hier nicht so deutlich klar, dass hier etwas erzeugt wird und wieder zerstört werden muss.

Code: Alles auswählen

var
  L: TStrings;
begin
  L := FindAllFiles(....);
  try
    Listbox1.Items := L;
  finally
    L.Free;
  end;

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von Ally »

Hallo Warf,
Aber wenn dir performance wirklich wert ist, ...
über die Performance hatte ich mir eigentlich keine Gedanken gemacht. Meine "Dateisuche" habe ich mal aus einem Beispiel, das ich im Netz gefunden habe, zusammengebaut.
Und das hat, verglichen mit der Windows-Suche, auch ganz gut funktioniert.
Als ich jetzt mal testweise "FindAllFiles" in mein Programm verwendet habe, habe ich mich halt gewundert, dass das auf einmal so langsam ist.
Danke für deinen iterativen Ansatz. Den werde ich natürlich auch noch testen.

Hallo wp_xyz,
muss man sich der Konsequenzen bewusst sein,
Ja das hatte ich im Wiki gelesen.
"Dateiliste" ist vom Typ TStringList, also nix passiert, kein Speicherleck. Nur das Tempo ist verbesserungswürdig.

Benutzeravatar
Ally
Beiträge: 263
Registriert: Do 11. Jun 2009, 09:25
OS, Lazarus, FPC: Win und Lazarus Stable release
CPU-Target: x64

Re: Rekursive Verzeichnis-Suche unter Linux (und Co)

Beitrag von Ally »

Die Sache hat mir jetzt doch keine Ruhe gelassen.
Ich habe gerade noch mal etwas eingehender getestet und herausgefunden, dass der Unterschied zwischen Theorie und Praxis in der Praxis größer ist als in der Theorie. :)
Beim ersten Herumprobieren war meine Routine tatsächlich deutlich schneller, aber, wie ich jetzt herausgefunden habe, nur beim wiederholten Aufrufen. Das wird wohl von Windows gecacht und bei erneuter Abfrage entsprechend schnell geliefert.
FindAllFiles liest wohl immer alles neu ein und braucht deshalb auch immer gleich lange.
Bei tieferen Verzeichnisstrukturen ist meine Routine zwar auch beim ersten Aufruf unmerklich schneller, dafür ist FindAllFiles bei flacheren Strukturen deutlich schneller.
Wer ein Verzeichnis nicht gerade mehrmals nacheinander durchsucht, ist mit FindAllFiles also an der richtigen Adresse.

Gruß Roland

Antworten