Autor Beitrag
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: So 17.08.03 20:41 
So, lange genug gewartet. Jetzt hole ich mir den Credit. :mrgreen:

Basierend auf diesem Beitrag habe ich einfach mal die Routine überarbeitet und auch ein wenig mit der bedingten Compilierung herumgespielt. Es wird hier vorausgesetzt, dass Pfad, Datum/Zeit und Dateiname in drei verschiedene Stringlisten (= 3 Listboxen) eingetragen werden sollen. Ich glaube aber nicht, dass es schwer ist, die Ausgabe in eine Listbox, ListView, ... umzuleiten ... Ist nur Software-Anpassung. :)
  1. Wie gehabt: der Formatstring für Datum und Uhrzeit ist zwar da, wird aber nicht benutzt. Er ist deaktiviert; Datum und Zeit werden nach den Einstellungen des Anwenders formatiert!
  2. Außerdem habe ich zwei Varianten eingebaut: seit vergangenen TurboPASCAL-Tagen verwende ich eigentlich immer while. Ich habe aber (nicht erst seit lambrucos Code) gesehen, dass viele lieber repeat benutzen. Wer sich also mit while nicht anfreunden kann, entfernt den Punkt in der Zeile
    ausblenden Delphi-Quelltext
    1:
    {.$DEFINE USE_REPEAT}					

    und die Prozedur arbeitet -dank bedingter Compilierung!- künftig mit while. Mich hat interessiert, ob das nun schneller ist. Mein Fazit: eigentlich nicht. Aber sei´s drum. :)
  3. Außerdem ist standardmäßig die Zählung von Dateien und Ordnern deaktiviert. Wer später eine Meldung ausgeben will, der entfernt auch den Punkt in der Zeile:
    ausblenden Delphi-Quelltext
    1:
    {.$DEFINE DEBUG_SHOWTIME}					

    Im Beispielaufruf kommt später der Rest (sprich: die Anzeige der Dialogbox, usw.)
  4. Zu guter Letzt ist zu beachten, dass das Arbeitsverzeichnis (das durchsucht werden soll) vor dem Aufruf der Prozedur zu setzen ist. Meine Pfadvariable "orgpath" im Prozedurkopf wird nicht verändert. Ich hab´s mir halt so angewöhnt. Sorry. :wink:

Hier nun die Funktion:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
{.$DEFINE USE_REPEAT}
{.$DEFINE DEBUG_SHOWTIME}

const
  szFormat = 'yyyy/mm/dd hh:nn:ss';

{$IFDEF DEBUG_SHOWTIME}
var
  iFile    : integer = 0;
  iFolder  : integer = 0;
  dwStart  : dword;
{$ENDIF}


procedure FindFiles(const orgpath: stringconst FindMask: TStringList;
  ResultPath, ResultDateTime, ResultFiles: TStrings;
  const fUseList:boolean=false);
var
  path : string;
{$IFNDEF USE_REPEAT}
  res  : integer;
{$ENDIF}
  ds   : TSearchRec;
begin
  if(orgpath = ''or                // kein Ausgangspfad
    (FindMask = nilor              // keine Dateiendungen
    (FindMask.Count = 0or
    (ResultPath = nilor            // keine Liste für den Pfad
    (ResultDateTime = nilor        // keine Liste für Datum/Uhrzeit
    (ResultFiles = nilthen exit;   // keine Liste für den Dateinamen

  // aktuellen Pfad ermitteln
  GetDir(0,path);

  // Dateien suchen
{$IFDEF USE_REPEAT}
  if(FindFirst('*.*',faAnyFile,ds) = 0then repeat
{$ELSE}
  res := FindFirst('*.*',faAnyFile,ds);
  while(res = 0do begin
{$ENDIF}
    // darf kein Ordner sein, und nicht "." oder ".."
    if(ds.Attr and faDirectory = 0and
      (ds.Name <> '.'and
      (ds.Name <> '..'then
    begin
{$IFDEF DEBUG_SHOWTIME}
      inc(iFile);
{$ENDIF}

      // die Endung der Datei darf NICHT in "FindMask" stehen
      // (fUseList = FALSE)
      if((not fUseList) and
         (FindMask.IndexOf(ExtractFileExt(ds.Name)) = -1)) or
      // die Endung der Datei MUSS in "FindMask" stehen
      // (fUseList = TRUE)
        ((fUseList) and
         (FindMask.IndexOf(ExtractFileExt(ds.Name)) <> -1)) then
      begin
        // aktuellen Pfad hinzufügen
        ResultPath.Add(path);

        // Datum & Zeit
        ResultDateTime.Add(FormatDateTime('' {szFormat},
          FileDateToDateTime(ds.Time)));

        // Dateiname
        ResultFiles.Add(ds.Name);
      end;

    end;
{$IFDEF USE_REPEAT}
  until(FindNext(ds) <> 0);
{$ELSE}
    res := FindNext(ds);
  end;
{$ENDIF}
  FindClose(ds);

  // ab in den nächsten Ordner
{$IFDEF USE_REPEAT}
  if(FindFirst('*.*',faDirectory,ds) = 0then repeat
{$ELSE}
  res := FindFirst('*.*',faDirectory,ds);
  while(res = 0do begin
{$ENDIF}
    // muss Ordner sein, aber nicht "." oder ".."
    if(ds.Attr and faDirectory <> 0and
      (ds.Name <> '.'and
      (ds.Name <> '..'then
    begin
{$IFDEF DEBUG_SHOWTIME}
      inc(iFolder);
{$ENDIF}

      ChDir    (ds.Name);
      FindFiles(orgPath,
        FindMask,
        ResultPath,
        ResultDateTime,
        ResultFiles,
        fUseList);
    end;
{$IFDEF USE_REPEAT}
  until(FindNext(ds) <> 0);
{$ELSE}
    res := FindNext(ds);
  end;
{$ENDIF}
  FindClose(ds);

  // einen Ordner nach oben (falls erforderlich)
  if(CompareText(path,orgpath) <> 0then ChDir('..');
end;


Und jetzt der Beispielaufruf in einem Buttonklick:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
procedure TForm1.Button1Click(Sender: TObject);
{$IFDEF DEBUG_SHOWTIME}
const
  szActionText  : array[boolean]of string =
    ('Der Ausschluss von','Die Suche nach');
{$ENDIF}
var
  fm            : TStringList;
  fIncludeFiles : boolean;
  szHomePath    : string;
begin
  fm := TStringList.Create;
  if(fm <> nilthen try
    fm.Add('.html');
    fm.Add('.htm');
    fm.Add('.shtml');

    ListBox1.Clear;
    ListBox2.Clear;
    ListBox3.Clear;
    ListBox1.Items.BeginUpdate;
    ListBox2.Items.BeginUpdate;
    ListBox3.Items.BeginUpdate;

{$IFDEF DEBUG_SHOWTIME}
    iFile         := 0;
    iFolder       := 0;
    dwStart       := GetTickCount;
{$ENDIF}

    // Ausgangsverzeichnis sichern
    szHomePath    := GetCurrentDir;

    // Als Beispiel: das Ausschlussverfahren; d.h. die
    // Dateiendungen in der Liste sollen bei der Suche
    // ignoriert werden!
    fIncludeFiles := FALSE;

    SetCurrentDir('d:\');
    FindFiles    ('d:\',  // <-- orgPath
      fm,                 // <-- Dateiliste
      Listbox1.Items,
      Listbox2.Items,
      Listbox3.Items,
      fIncludeFiles       // <-- Suchen, oder Ausschließen?
    );

    // Ausgangsverzeichnis setzen
    SetCurrentDir(szHomePath);

{$IFDEF DEBUG_SHOWTIME}
    dwStart       := GetTickCount - dwStart;
{$ENDIF}

    ListBox1.Items.EndUpdate;
    ListBox2.Items.EndUpdate;
    ListBox3.Items.EndUpdate;

{$IFDEF DEBUG_SHOWTIME}
    ShowMessage(Format(
      '%s %d Dateitypen benötigte %d msec bei %d Dateien und %d Ordnern.',
      [szActionText[fIncludeFiles],fm.Count,dwStart,iFile,iFolder]));
{$ENDIF}
  finally
    fm.Free;
  end;
end;

Damit würden alle Dateien aufgelistet werden - außer HTML, HTM und SHTML. Wer stattdessen nur HTML-, HTM- und SHTML-Dateien anzeigen lassen möchte, ändert lediglich die Bool-Variable:
ausblenden Delphi-Quelltext
1:
    fIncludeFiles := TRUE;					

Das war´s. Sieht da wer durch? :wink:

(btw: Ich habe mal meine C-Partition (Win98) nach HTML, HTM und SHTML scannen lassen. Wie gehabt kam es zur schon mal erwähnten "Eigenart" von FindFirst und Co. Beim allerersten Start (quasi nach dem Hochfahren des Rechners) brauchte die obige Funktion ~10 Sekunden, um 21.188 Dateien und 1.867 Ordner zu durchsuchen. Beim zweiten Versuch, gleich danach!, nur noch ~4 Sekunden.
Erklären kann ich es nicht. Ich kann nur raten, dass die Ergebnisse irgendwie indiziert oder auf andere Art "gemerkt" werden, sonst käme es nicht zu einem Zeitunterschied von 9 Sekunden.)



Mit Dank an lambruco für die Idee.


Zuletzt bearbeitet von MathiasSimmack am Mo 18.08.03 09:38, insgesamt 1-mal bearbeitet