Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Schnellste Möglichkeit einen Verzeichnisbaum einzulesen (https://www.delphipraxis.net/216324-schnellste-moeglichkeit-einen-verzeichnisbaum-einzulesen.html)

Hobbycoder 10. Dez 2024 09:50

Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Hi,

ich muss einen Verzeichnisbaum einlesen und dabei Dateinamen, Dateigröße und Erstellungsdatum einlesen und mit einer Datenbank abgleichen. Tatsächlich handelt es sich nur um 2 Verzeichnisebenen. Allerdings immer über Netzwerk.
Zur Zeit nutze ich FindFirst/FindNext, und das dann recursiv. Es handelt ich ca. um 37000 Dateien.
Leider dauert das verhältnismäßig lange im Vergleich zur danach folgenden Datenbankoperation.

Gibt es schon signifikant schnellere Möglichkeiten, oder ist da nicht mehr viel rauszuholen?

Delphi-Quellcode:
procedure TThreadLoadBilderArchivieren.BilderEinlesen(
  Pfad: string);
var
  sr: TSearchRec;
  b: TBild;
begin
  if self.Terminated then Exit;
  if FindFirst(Pfad+'*.*', faAnyFile, sr)=0 then
  repeat
    if (sr.Name<>'.') and (sr.Name<>'..') and (LowerCase(sr.Name)<>'thumbs.db') then
    begin
      if sr.Attr and faDirectory = faDirectory then
      begin
        BilderEinlesen(Pfad+sr.Name+'\');
      end else begin
        if ExtractFileExt(sr.Name)<>'.tmb' then
        begin
          b:=TBild.Create;
          b.lfdnr:=0;
          b.Pfad:=Pfad+sr.Name;
          b.Dateidatum:=FileDateToDateTime(sr.Time);
          b.Groesse:=sr.size;
          FBildList.Add(b);
        end;
      end;
    end;
    if self.Terminated then Break;
  until FindNext(sr)<>0;
  sysutils.FindClose(sr);
end;

himitsu 10. Dez 2024 09:55

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Nimm direkt die WinAPI Bei Google suchenFindFirstFile und da gibt es Optionen, um Zusatzinfos wegzulassen (vor allem den 8.3-Dateiname), die Sortierung des Treibers und "LargeFetch".


PS: Aktuelle Delphis haben im TSearchRec ein Property, was dir direkt den TDateTime gibt. (ohne manuelles FileDateToDateTime)
https://docwiki.embarcadero.com/Libr...ils.TSearchRec

Tipp: Vielleicht nicht unbedingt schneller, aber "einfacher":
Delphi-Referenz durchsuchenTDirectory.GetFiles
https://www.delphipraxis.net/216317-...ei-finden.html

Hobbycoder 10. Dez 2024 10:01

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Danke

Zitat:

PS: Aktuelle Delphis haben im TSearchRec ein Property, was dir direkt den TDateTime gibt. (ohne manuelles FileDateToDateTime)
https://docwiki.embarcadero.com/Libr...ils.TSearchRec

Tipp: Vielleicht nicht unbedingt schneller, aber "einfacher":
Delphi-Referenz durchsuchenTDirectory.GetFiles
Leider noch auf einem alten D7 :-D
Aber die WinAPI werd ich mal ausprobieren.

himitsu 10. Dez 2024 10:06

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Zitat:

Zitat von Hobbycoder (Beitrag 1544070)
Leider noch auf einem alten D7 :-D

https://www.embarcadero.com/de/products/delphi/starter

https://www.delphipraxis.net/profile.php?do=editprofile da unten kann man was angeben :zwinker:


Und wegen Delphi 7:
Die Unicode-Version (W), nicht ANSI (A).

Bzw. direkt MSDN-Library durchsuchenFindFirstFileExW mit BasicLevel anstatt MSDN-Library durchsuchenFindFirstFileW.

Delphi.Narium 10. Dez 2024 10:21

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Kannst Du mal vergleichen, ob deine Routine lokal (mit der passender Datenmenge) deutlich schneller ist, als über das Netz.

Meine D7-Variante für rekursives Dateiensuchen sieht Deiner Routine verblüffend ähnlich und ist sehr schnell. Den Flaschenhals vermute ich daher im Netzwerkzugriff und nicht in Deiner Routine.

Hobbycoder 10. Dez 2024 14:50

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Zitat:

Zitat von himitsu (Beitrag 1544071)
Zitat:

Zitat von Hobbycoder (Beitrag 1544070)
Leider noch auf einem alten D7 :-D

https://www.embarcadero.com/de/products/delphi/starter

https://www.delphipraxis.net/profile.php?do=editprofile da unten kann man was angeben :zwinker:

Ist mir bekannt. Ist aber ein altes Projekt, dass ich jetzt nicht deswegen komplett überarbeiten will.

Hobbycoder 10. Dez 2024 14:54

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1544072)
Kannst Du mal vergleichen, ob deine Routine lokal (mit der passender Datenmenge) deutlich schneller ist, als über das Netz.

Meine D7-Variante für rekursives Dateiensuchen sieht Deiner Routine verblüffend ähnlich und ist sehr schnell. Den Flaschenhals vermute ich daher im Netzwerkzugriff und nicht in Deiner Routine.

So unterschiedlich können recursive Methoden, die FindFist/FindNext nutzen, nicht aussehen ;-)

Ist möglich. Aber das Netzwerk beim Kunden liegt nicht unter meiner Kontrolle. Das muss ich in dem Fall so nehmen wie es ist.
Ich kann (will) mir jetzt aber auch nicht die ganzen 37000 Dateien rüberholen um das bei mir zu testen ;-)

Delphi.Narium 10. Dez 2024 18:00

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Du muss Dir ja nicht die Dateien des Kunden holen, es reicht ja, wenn Du Dir einen passenden Verzeichnisbaum mit (durchaus auch leeren Dateien) anlegst.

Oder nimm einfach Laufwerk C: und miss die Zeit. Zeit durch Anzahl Dateien = Durchschnittswert * 37.000 wäre die zu erwartende Zeit. Gibt's da große Unterschiede oder ist das eher vernachlässigbar? Große Unterschiede hieße für mich, dass der Flaschenhals eher im Netzwerk zu suchen ist, andernfalls in Deiner Routine.

jaenicke 10. Dez 2024 20:20

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Der Flaschenhals ist hier die Latenz beim Zugriff auf den Server. Es wird für jeden Abruf der jeweils nächsten Datei eine Anfrage an den Server geschickt und darauf gewartet.

Lösen kann man das auf zwei Wegen:
  • Du kannst die Abfrage mit mehreren Threads erledigen, indem du z.B. einen Thread pro Anfangsbuchstabe erstellst oder einen pro Unterverzeichnis oder ähnliches, je nachdem was passt. Anders als bei lokalen Abfragen ist die eingesparte Wartezeit auf die Antworten des Servers größer als die Verlangsamung durch parallele Abfragen ins Dateisystem. In aktuellen Delphis kann man dafür TTask oder parallel for verwenden, bei Delphi 7 kannst du TThread nutzen.
  • Am besten ist aber die Nutzung einer SMB-Bibliothek wie libsmb2. Diese hat den großen Vorteil, dass smb2_opendir und smb2_readdir die Dateiinformationen direkt in einem Puffer abrufen, so dass nicht bei jeder Datei einzeln eine Anfrage an den Server geschickt wird. Wenn man den verwendeten Puffer im System noch erhöhen kann, erhöht sich die Geschwindigkeit zusätzlich.
    Die Implementierung ist relativ einfach, da nur ein paar exportierte Funktionen und Strukturen übersetzt werden müssen.

Hobbycoder 11. Dez 2024 10:47

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
Zitat:

Zitat von jaenicke (Beitrag 1544094)
Am besten ist aber die Nutzung einer SMB-Bibliothek wie libsmb2. Diese hat den großen Vorteil, dass smb2_opendir und smb2_readdir die Dateiinformationen direkt in einem Puffer abrufen, so dass nicht bei jeder Datei einzeln eine Anfrage an den Server geschickt wird. Wenn man den verwendeten Puffer im System noch erhöhen kann, erhöht sich die Geschwindigkeit zusätzlich.
Die Implementierung ist relativ einfach, da nur ein paar exportierte Funktionen und Strukturen übersetzt werden müssen.

Das werd ich mal ausprobieren. Klingt sehr gut :thumb:

dummzeuch 11. Dez 2024 12:39

AW: Schnellste Möglichkeit einen Verzeichnisbaum einzulesen
 
So am Rande bemerkt: Caching, auch Client Side Caching im Netzwerk, kann einen ziemlich großen Einfluss auf die Performance haben. Insofern ist es nicht ganz einfach, da was sinnvolles zu messen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:08 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz