Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi ListFiles mit FindFirst beschleunigen (https://www.delphipraxis.net/146032-listfiles-mit-findfirst-beschleunigen.html)

Moony 12. Jan 2010 15:01


ListFiles mit FindFirst beschleunigen
 
Hallo zusammen,

ich habe bei meiner Applikation mittlerweile festgestellt, dass die Routine zum Auflisten bestimmter Dateien in einem Verzeichnis bei knapp 3500 Dateien ca. 15 Sekunden dauert. Ich suche mit folgender Routine das Verzeichnis ab:

Delphi-Quellcode:
procedure ListFiles(Path, Ext: string; FileList: TStringList; Attr: integer);
var
  SR : TSearchRec;
begin
  if Length(Path) > 0 then
    Path := IncludeTrailingBackslash(Path);

  if FindFirst(Path + Ext, faAnyFile, SR) = 0 then
  begin
    repeat
      if (SR.Attr <> faDirectory) then
      begin
         if (fmPhoto.ImageSet.CheckAttr) and (not fmPhoto.DoRefreshAll) then
          if (SR.Attr and Attr) = 0 then
            Continue;

         if UpperCase(ExtractFileExt(SR.Name)) = UpperCase(ExtractFileExt(Ext)) then
          FileList.Add(SR.Name);
      end;
    until FindNext(SR) <> 0;
    SysUtils.FindClose(SR);
  end;
end;
Sind die Kriterien erfüllt worden, wird dann außerhalb dieser Routine weiter mit den einzelnen Dateien gearbeitet.

Wie kann man also diese Routine optimieren bzw. beschleunigen?

Danke & Gruß, Moony

himitsu 12. Jan 2010 15:05

Re: ListFiles mit FindFirst beschleunigen
 
FindFirst ist von Haus aus langsam. (einzige Lösung wäre die MFT direkt auszulesen, aber das ist nicht unbedingt so einfach)

Was du aber machen kannst (es kommt darauf an, was sich hinter der Stringliste versteckt), wäre deren Updaten per Delphi-Referenz durchsuchenBeginUpdate abzuschalten.

Bernhard Geyer 12. Jan 2010 15:06

Re: ListFiles mit FindFirst beschleunigen
 
Z.B.
Delphi-Quellcode:
UpperCase(ExtractFileExt(Ext))
nur einmal am Anfang der Funktion machen.

Und da wir nicht wissen was
Delphi-Quellcode:
(fmPhoto.ImageSet.CheckAttr) and (not fmPhoto.DoRefreshAll)
ist evtl. das die Bremse (Profiler würde helfen)

Moony 12. Jan 2010 15:37

Re: ListFiles mit FindFirst beschleunigen
 
Oh, sorry.

Das
Delphi-Quellcode:
(fmPhoto.ImageSet.CheckAttr) and (not fmPhoto.DoRefreshAll)
sind Boolean-Variablen einfach nur um zu prüfen ob ich alle Dateien mit der Endung nehmen soll oder nur die mit der angegebenem Attribut.

Das Uppercase nur einmal aufzurufen hat keine Verbesserung gebracht.

@himitsu: Die Stringliste wird leer übergeben und in dieser Routine ggf. gefüllt, damit ich weiter mit den benötigten Dateien arbeiten kann. Wie kann ich das denn mit MFT lösen bzw. in wie weit hilft mir BeginUpdate weiter?

Gruß

ChrisE 12. Jan 2010 16:14

Re: ListFiles mit FindFirst beschleunigen
 
Hallo,

wo suchst du die Dateien? Lokal auf der Festplatte oder im Netzwerk?
Welches Betriebssystem verwendest du?
Wenn du mehrfach im selben Verzeichnis suchst, ändert sich die Zeit?
Befinden sich andere Dateien in dem Verzeichnis, die die Suchkriterien nicht erfüllen (z.B. andere Dateiendung)

Das sind so die Kriterien, nach den ich diese Suchalgorithmen angepackt habe.

Aber es ist tatsächlich so, dass es Situationen gibt, bei denen man nicht schneller werden kannst. Selbst MS versucht dieses Problem an zu gehen durch Indizierung der Dateien oder andere File-Systeme die eine Suche ermöglichen.

Aber das hilft dir ja erstmal nicht weiter.

Greez, Chris

Moony 13. Jan 2010 07:33

Re: ListFiles mit FindFirst beschleunigen
 
Also, die Dateisuche findet fast immer über ein lokales Netzwerk statt. In den Verzeichnissen sind fast immer nur die Dateien drin, welche die gesuchte Endung besitzen, ist aber keine Sicherheit dass es so ist. Es sind ebenfalls Dateien im Verzeichnis, welche die Suchkriterien nicht erfüllen. Es kommt also auch mal vor, dass ein Verzeichnis durchlaufen wird, aber keine zutreffende Datei gefunden wird.

ChrisE 13. Jan 2010 08:17

Re: ListFiles mit FindFirst beschleunigen
 
Hallo Moony,

Über das Netzwerk ist es tatsächlich so, dass die Zeiten deutlich länger sind als auf Lokalen Festplatten des Rechners.

Deinen Algo würde ich erstmal so anpassen wie auch schon von anderen vorgeschlagen:

Delphi-Quellcode:
procedure ListFiles(Path, Ext: string; FileList: TStrings; Attr: integer);
var
  SR : TSearchRec;
  CheckAttrAndNotRefreshAll : Boolean; // neu
begin
  if Length(Path) > 0 then
    Path := IncludeTrailingBackslash(Path);

  //Ext := UpperCase(Ext); // neu
  CheckAttrAndNotRefreshAll := (fmPhoto.ImageSet.CheckAttr) and (not fmPhoto.DoRefreshAll); // neu

  if FindFirst(Path + '*' + Ext, faAnyFile, SR) = 0 then // Stern eingefügt
  begin
    FileList.BeginUpdate;
    try
      repeat
        if (SR.Attr and faDirectory) = 0 then
        begin
           if CheckAttrAndNotRefreshAll then
           begin
             if (SR.Attr and Attr) = 0 then
               Continue;
           end;

           // Brauchst du das Hier wirklich? 
           //if UpperCase(ExtractFileExt(SR.Name)) = Ext then
           //begin
             FileList.Add(SR.Name);
           //end;
        end;
      until FindNext(SR) <> 0;
    finally
      FileList.Endupdate;
    end;
    SysUtils.FindClose(SR);
  end;
end;
Wobei ich nicht ganz verstehe, wie du die MEthode aufrufst. Bei mir würde meine Version so aussehen:
Delphi-Quellcode:
Listfiles('X:\TestVieleDateien', '.jpg', ListBox1.Items, 0);
Somit wird auch der Vergleich auf die Variable Ext unnötig. Oder hab ich das jetzt was falsch verstanden?

Greez, Chris

[EDIT]Quelltext angepasst wegen Beitrag #9, #11, #13. Danke DeddyH und himitsu[/EDIT]

himitsu 13. Jan 2010 08:34

Re: ListFiles mit FindFirst beschleunigen
 
MFT (MasterFileTable) ist 'ne Kontrollstruktur innerhalb einer NTFS-Partition ... kann man also nur nutzen, wenn man direkten Zugriff auf dieses Laufwerk hätte ... also im Netzwerk geht sowas nicht.

Wenn noch andere Dateien im Verzeichnis vorhanden sind, neben jenen, welche deiner gesuchten "Dateierweiterung" (EXT), dann könnte es schon was bringen, wenn man nicht erstmal alles sucht und danach filtert.

Die einzige Möglichkeit, welche danach noch eine Beschleunigung bringen würde, wäre das Verzeichnis lokal auszulesen und sich die Liste komplett über's Netzwerk zu schicken.
Also ein Programm auf der anderen Netzwerkseite, welche das direkt ausließt und alles zusammen in einem Datenstrom zu deinem Programm schickt.

DeddyH 13. Jan 2010 08:50

Re: ListFiles mit FindFirst beschleunigen
 
Bissel OT: Ich frage mich die ganze Zeit, ob diese Zeile wirklich richtig ist:
Zitat:

Delphi-Quellcode:
if (SR.Attr <> faDirectory) then

:gruebel:

ChrisE 13. Jan 2010 08:53

Re: ListFiles mit FindFirst beschleunigen
 
Zitat:

Zitat von DeddyH
Bissel OT: Ich frage mich die ganze Zeit, ob diese Zeile wirklich richtig ist:
Zitat:

Delphi-Quellcode:
if (SR.Attr <> faDirectory) then

:gruebel:

Es scheint zu funktionieren, aber besser wäre sicher
Delphi-Quellcode:
if (SR.Attr and faDirectory) <> faDirectory then
Da stimme ich dir zu.

Greez, Chris


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:35 Uhr.
Seite 1 von 2  1 2      

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