Einzelnen Beitrag anzeigen

Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#7

Re: schnellere Procedure gesucht

  Alt 20. Dez 2005, 06:14
Delphi-Quellcode:
procedure Tmediaarchiv_frm.AllFilesWithExtension(const Path: String; List, Extenstions: TStrings);
var
  Tick: Cardinal;

  procedure DoSearch(const Path: String);
  var
    SR: TSearchRec;
  begin
    if FindFirst(Path + '*.*', faAnyFile, SR) = 0 then
    try
      repeat
        if GetTickCount >= Tick then
        begin
          Tick := GetTickCount + 100;
          Application.ProcessMessages;
        end;
  
        if (SR.Attr and faDirectory <> 0) and (SR.Name <> '.') and (SR.Name <> '..') then
          DoSearch(Path + SR.Name + '\')
        else
          if Extension.IndexOf(ExtractFileExt(SR.Name)) >= 0 then
            List.Add(Path + SR.Name);

      until FindNext(SR) <> 0;
    finally
      FindClose(SR);
    end;

begin
  List.BeginUpdate;
  try
    Tick := GetTickCount + 100;
    DoSearch(ExtractFilePath(Path) + '\');
  finally
    List.EndUpdate;
  end;
end;

Mehrere Bemerkungen:

1.) Parameter, besonders LongsString sollten CONST sein und nicht ständig geändert werden. In deinem original Code rufst du rekursiv immer den Pfad OHNE Delimiter auf und erzeugst mit Folder := IncludeTrailingPathDelimiter(folder) ständig Kopien des Strings. Bei einer Ordnerbaumtiefe von 10 Ebenen würde deine originale Routinen also 10 temporäre Strings mehr auf dem Stack speichern. Obige Methode geht anders vor indem sie von Anfang an sicher stellt das Path ein CONST ist und schon beim Aufrufe korrekt mit '\' expandiert wurde.

2.) List == mediaplayer_frm.PlayList_ListBox.Items wird mit .BeginUpdate/.EndUpdate gelockt und somit nicht ständig neu gezeichnet. Die TStrings dieser VCL Objekte wie TListBox, TMemo, TComboBox sind nur Handler um direkt auf das Windows Fenster Handle mit seiner internen Liste zuzugreifen. Das dauert alles sehr sehr lange und ist ineffizient.

3.) Ein ständiger Aufruf von Application.ProcesssMessages ist immer schlecht. Erstens weil in deinem Source der Aufruf viel zu häufig erfolgte und zweitens weil die Methode Tmediaarchiv_frm.AllFilesWithExtension() nicht mehr reentrant ist. Das bedeutet das durch den Aufruf von Application.ProcessMessages könnte der Benutzer einen Buttondrücken der dann wiederum Tmediaarchiv_frm.AllFilesWithExtension() aufruft. Es entsteht also eine "Rekursion" durch Mehrfachaufruf von Tmediaarchiv_frm.AllFilesWithExtension() die aber immer auf der gleichen Liste arbeitet !!
Man muß also sicherstellen das Tmediaarchiv_frm.AllFilesWithExtension() nicht merhfach aufgerufen werden kann, zb. indm man die Buttons disabled.

4.) if (SR.Attr and faDirectory) = faDirectory then, ist nicht nur ineffizienter sondern könnte auch fehlerhaft sein. Dies ist ein Integer-Vergleich und keine Boolsche Abfrage mehr. Falls faDirectory zb. $80000000 wäre, also das Vorzeichenbit eines Integer und SR.Attr als Integer deklariert wäre so würde es unter Umständen zb. in Delphi <= version 3 falsch Abfragen erzeugt.
Besser ist also if SR.Attr and faDirectory <> 0 then;

5.) eine Abfrage von SR.Name = '.' or SR.Name = '..' aber ohne faDirectory ist falsch. Die Bedingung lautet

"wenn Directory und Name nicht '.' und Name nicht '..'" ist dann gehe rekusiv weiter !

Deine Abfrage führt dazu das reguläre Dateien mit Namen '.' oder '..' nicht gefunden werden.
Es ist irrelevant ob laut MS-DOS oder FAT Treiber solche Dateinamen garnicht möglich sind, sie könnten unter Linux/Kylix/Unix oder Win3199 sehr wohl gültig sein.


6.) Performanceverbesserungen:
- Application.ProcessMessages nur alle 100 Millisekunden
- List.Add() führt nicht zum ständigen langsammen Neuzeichnen des GUIs, da .gelockt per .BeginUpdate, .EndUpdate
- unötige Funktion IncludeTrailingPathDelimiter() konnte entfernt werden weil der rekursive Aufrufer mit seinem schon vorhandenen Wissen den Path "in advance" korrekt formatieren kann.
- unnötige LongString Kopien von Path auf dem Stack entfernt
- Boolsche Abfrage (SR.Attr and faDirectory <> 0) and (SR.Name <> '.') and (SR.Name <> '..') in der Reihenfolge optimiert. Falls (SR.Attr and faDirectory <> 0) nicht zutrifft wird auch nicht der langsamme Stringvergleich in (SR.Name <> '.') and (SR.Name <> '..') durchgeführt.

Gruß Hagen
  Mit Zitat antworten Zitat