Autor Beitrag
lambruco
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 100

Win 2000/2000 Server/XP
D6 Prof.
BeitragVerfasst: Mi 16.07.03 11:02 
Wie man Verzeichnisse rekursiv durchsucht, ist ja in der FAQ erkärt und läuft auch wunderbar, aber man kann nur nach allen bzw. bestimmten Dateien suchen. Was muss ich aber machen, wenn ich nach allen Dateien suchen will und bestimmte Dateien nicht anzeigen will. Ich dachte es mir so, aber leider klappt es nicht.

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:
Procedure UGrid1.FindFiles (Path: String;FindMask:TStringlist;ResultPath,
                            ResultDateTime,ResultFiles: tStrings);
Var
  FindRec: tSearchRec;
  format: string;
  cnt : Integer;
begin
  format := 'yyyy/mm/dd hh:nn:ss';
  If (Path = ''or (FindMask.count < 0or Not Assigned (ResultPath) Then
    Exit;
  If Path[Length (Path)] <> '\' Then
    Path := Path + '\';
  for cnt:=0 to Findmask.count-1 do
    begin
      If FindFirst (Path + '*.*', faAnyFile, FindRec) = 0 Then
        Repeat
          If (FindRec.Name <> '.'and (FindRec.Name <> '..')
              and (FindRec.Attr<>faDirectory) Then
          if CheckMask(FindRec.name,Findmask[cnt]) then
            begin
              ResultPath.Add (Path);
              if fileage(path+findrec.Name) <> -1 then
                begin
                  ResultDateTime.Add(FormatDateTime(format,FileDateToDateTime(
                                      fileage(path+findrec.Name))));
                end;
              ResultFiles.add (FindRec.Name);
            end;
      Until FindNext (FindRec) <> 0;
      FindClose (FindRec);
   end;
  If FindFirst (Path + '*.*', faAnyFile, FindRec) = 0 Then
      Repeat
        If (FindRec.Name <> '.'and (FindRec.Name <> '..'Then
           If Boolean (FindRec.Attr and faDirectory) Then
              FindFiles (Path + FindRec.Name,FindMask,ResultPath,
                         ResultDateTime,ResultFiles);
      Until FindNext (FindRec) <> 0;

    FindClose (FindRec);

End;

function UGrid1.CheckMask(s,mask : String):boolean;
var
  i     : Integer;
  sPart : String;
begin
   sPart := '' ;
   i :=2;
   repeat
     sPart := token(s,'.',i); //token liefert Teilstrings zB token 
                             //('format.exe','.',1) liefert 'format'
     if sPart <> '' then
        sPart := '.'+sPart;
     if AnsiCompareText(sPart,mask)=0 then
       begin
         result := false;
         exit;
       end;
     inc(i)
   until sPart = '';
   result := true;
end;


Moderiert von user profile iconUGrohne: Code- durch Delphi-Tags ersetzt

_________________
Wer Rechtschreibfehler findet, kann Sie behalten
GruppeCN
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 322



BeitragVerfasst: Sa 19.07.03 16:15 
Laut Titel ist dein Problem gelöst. :lol: Vielleicht postest du mal den richtigen Code, die Lösung, ...

_________________
Warum sind die Sachen, die du suchst, immer da, wo du zuletzt nachsiehst?
Weil du aufhörst zu suchen, wenn du sie gefunden hast.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 19.07.03 20:06 
Titel: Edited on Sun-day
Ich halte den Ansatz von lambruco (ob nun gelöst oder nicht) nicht für eine optimale Lösung. Das liegt an der Konstruktion hier:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
  for cnt:=0 to Findmask.count-1 do
    begin
      If FindFirst (Path + '*.*', faAnyFile, FindRec) = 0 Then
        Repeat
          { ... }
        Until FindNext (FindRec) <> 0;
      FindClose (FindRec);
   end;

Das ist sehr zeitraubend. Angenommen, du hast 10 Einträge in "FindMask" und 1.000 Dateien im Ordner, dann durchläufst du mit obiger Variante 10x 1.000 Dateien. Besser wär´s anders herum: alle Dateien scannen und dann erst prüfen, ob die Endung vorkommt oder nicht. Und auch das geht ohne for-Schleife ab.

Folgende Routine stelle ich zur Diskussion. Ich habe zwar den Formatstring übernommen, aber er ist im Code deaktiviert, damit bei der Anzeige von Datum und Zeit meine Systemeinstellungen berücksichtigt werden:
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:
const
  szFormat = 'yyyy/mm/dd hh:nn:ss';
  // umbenannt in "szFormat", weil "Format" auch der Name
  // einer Funktion ist!

procedure FindFiles(const orgpath: stringconst FindMask: TStringList;
  ResultPath, ResultDateTime, ResultFiles: TStrings);
var
  path : string;
  res  : integer;
  ds   : TSearchRec;
  iAge : integer;
begin
  if(FindMask = nilor
    (FindMask.Count = 0or
    (ResultPath = nilor
    (ResultDateTime = nilor
    (ResultFiles = nilthen exit;

  // aktuellen Pfad ermitteln
  path := GetCurrentDir;

  // Dateien suchen
  res  := FindFirst('*.*',faAnyFile,ds);
  while(res = 0do begin
    // darf kein Ordner sein, und nicht "." oder ".."
    if(ds.Attr and faDirectory = 0and
      (ds.Name <> '.'and
      (ds.Name <> '..'then
    // die Endung der Datei darf NICHT in "FindMask" stehen
    if(FindMask.IndexOf(ExtractFileExt(ds.Name)) = -1then begin
      // aktuellen Pfad hinzufügen
      ResultPath.Add(path);

      // Datum & Zeit
      iAge := FileAge(path + '\' + ds.Name);
      if(iAge <> -1then
        ResultDateTime.Add(FormatDateTime('' {szFormat},
          FileDateToDateTime(iAge)))
      else
        ResultDateTime.Add('-unbekannt-');
      // für den unwahrscheinlichen Fall, dass Datum & Zeit
      // nicht ermittelt werden können, sollte trotzdem
      // etwas eingetragen werden, weil sich die Anzahl der
      // Strings in den 3 Listen sonst unterscheidet


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

    res := FindNext(ds);
  end;
  FindClose(ds);

  // ab in den nächsten Ordner
  res  := FindFirst('*.*',faAnyFile,ds);
  while(res = 0do begin
    // muss Ordner sein, aber nicht "." oder ".."
    if(ds.Attr and faDirectory <> 0and
      (ds.Name <> '.'and
      (ds.Name <> '..'then
    begin
      ChDir    (ds.Name);
      FindFiles(orgPath,
        FindMask,
        ResultPath,
        ResultDateTime,
        ResultFiles);
    end;

    res := FindNext(ds);
  end;
  FindClose(ds);

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

Anwendungsbeispiel:
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:
procedure TForm1.Button1Click(Sender: TObject);
var
  fm : TStringList;
begin
  fm := TStringList.Create;
  if(fm <> nilthen try
    fm.Add('.html');
    fm.Add('.htm');
    fm.Add('.zip');
    fm.Add('.rar');
    { ... }


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

    SetCurrentDir('L:\');
    FindFiles    ('L:\',
      fm,
      Listbox1.Items,
      Listbox2.Items,
      Listbox3.Items);

    ListBox1.Items.EndUpdate;
    ListBox2.Items.EndUpdate;
    ListBox3.Items.EndUpdate;
  finally
    fm.Free;
  end;
end;

So sehe ich in den 3 Listboxen alle Dateien (sowie Pfad und Datum/Zeit) außer HTML, HTM, ZIP und RAR. :)



Geändert von mir: kleiner Fix, und Kommentar geändert :mrgreen:
lambruco Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 100

Win 2000/2000 Server/XP
D6 Prof.
BeitragVerfasst: Mo 21.07.03 07:47 
moin Simmack,

finde deinen Ansatzt sehr interessant, werde ihn heute mal testen und die
Zeit messen.
Ergebnis folgt später ( gehe aber davon aus, das deine Version gerade bei grösseren Datenmengen schneller sein wird).
Bis später

Lars

_________________
Wer Rechtschreibfehler findet, kann Sie behalten
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 21.07.03 07:54 
Titel: OFF-TOPIC
Es soll nicht der Eindruck entstehen, als wäre ich beleidigt ... oder so ... aber ich hab´s bisher immer so gehalten, dass ich die Leute mit ihren Benutzernamen anrede. Oder wenn ich irgendwie und irgendwo einen eindeutig erkennbaren Vornamen sehe, dann verwende ich meist auch nur diesen.

Will sagen: wenn so
lambruco hat folgendes geschrieben:
moin Simmack,

dann bitte mit "Herr" davor, sonst wirkt es sehr unhöflich.
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 21.07.03 10:54 
Eine kleine Anekdote zu meinem Test:

Ich war kurz davor, neidisch zu werden und meine Aussagen zu überdenken. Bei nämlich nur zwei unerwünschten Dateiendungen in "FindMask" (HTML und HTM) war deine Funktion (s. oben) plötzlich extrem schnell. Bis ich dann merkte, dass ich versehentlich meinen Code aufrief. :oops: Wie man sehen kann, heißt meine Prozedur ja auch
ausblenden Delphi-Quelltext
1:
2:
procedure FindFiles(const orgpath: stringconst FindMask: TStringList;
  ResultPath, ResultDateTime, ResultFiles: TStrings);

Ich habe deine Routine ja 1:1 übernommen und nur in "lamb_FindFiles" umbenannt. Und weil sie sich im Ordnerteil selbst aufruft, dort aber noch der alte Name stand, wurde eben mein Code ausgeführt. :) Also habe ich´s geändert, und dann ging nichts mehr. Ich musste erst mal ein paar Bugs in deiner Prozedur beheben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
  for cnt := 0 to FindMask.Count - 1 do begin
    if(FindFirst(Path + '*.*',faAnyFile,FindRec) = 0then repeat
      if(FindRec.Name <> '.'and
        (FindRec.Name <> '..'and
        (FindRec.Attr and faDirectory = 0then

und
ausblenden Delphi-Quelltext
1:
2:
3:
4:
  if FindFirst(Path + '*.*', faDirectory, FindRec) = 0 then repeat
    If(FindRec.Name <> '.'and
      (FindRec.Name <> '..'and
      (FindRec.Attr and faDirectory <> 0Then

um wenigstens ein Ergebnis erzielen zu können. Und dann musste ich bei deiner Funktion noch tricksen, weil ich zur Kontrolle die Dateien und Ordner zählen wollte. Da du aber auf Grund der primären for-Schleife die Dateien mehrfach scannst (und sie dadurch auch mehrfach gezählt werden würden :wink:), musste ich das vom Schleifenwert abhängig machen:
ausblenden Delphi-Quelltext
1:
        if(cnt = 0then inc(iFile);					


Fazit: eine CD mit 1969 Dateien und 248 Ordnern wurde von deiner Prozedur in 3 Sekunden gescannt. Meine brauchte 250 Millisekunden. 7 Dateitypen (HTML, HTM, SHTML, RAR, ZIP, PNG und JPG) waren dabei unerwünscht.

Deine Routine macht allerdings Boden gut, wenn es tatsächlich nur wenig Dateiendungen in "FindMask" gibt. Bei nur 1 Dateiendung (HTML) brauchte deine Routine nur noch 519 Millisekunden, während meine langsamer wurde: 409 Millisekunden.

Damit bestätigt sich meine Behauptung im ersten Posting: je mehr Endungen in deiner "FindMask" stehen, desto länger dauert es, weil die for-Schleife entsprechend oft durchlaufen werden muss. Im Gegensatz dazu wird meine Funktion sogar schneller, je mehr Endungen du angibst. :)

Gruß.
lambruco Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 100

Win 2000/2000 Server/XP
D6 Prof.
BeitragVerfasst: Mo 21.07.03 12:12 
Sehr geehrter Mathias,

erst einmal wollte ich nicht unhöflich sein; es ist einfach eine norddeutsche Art, statt des Vornamen den Nachnamen zu benutzen. Ich hoffe, es bereitet ihnen keine Probleme, wenn ich Sie duze, da es anscheinend der normale Umgangston im Forum ist.

Jetzt mal zu deiner Funktion, schon auf dem ersten Blick war ich mir sicher, das Sie schneller laufen würde, aber ich versuche sie gerade noch ein wenig zu verbessern. Die Funktion erhält einen weiteren Parameter (boolean), der entscheidet, ob es sich um eine "Auswahl-Liste" oder um eine "Ausschluss-Liste" handelt.

Ansonsten nichts für Ungut und vielen Dank für die Verbesserungsvorschläge (programiere erst seit 5 Mon)

Gruß Lars

_________________
Wer Rechtschreibfehler findet, kann Sie behalten
MathiasSimmack
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 21.07.03 12:26 
lambruco hat folgendes geschrieben:
Sehr geehrter Mathias,

Hm, das ist auch nich´ besser. :mrgreen:

Zitat:
Ansonsten nichts für Ungut und vielen Dank für die Verbesserungsvorschläge (programiere erst seit 5 Mon)

Keine Ursache. Du hast ja selbst gesagt, dass deine Funktion nicht so ganz klappte. Außerdem war´s kein Vorwurf, sondern es hat mich ja selbst interessiert, wie meine Funktion denn nun abschneidet. :)

btw: Das hier (s. meine Funktion)
ausblenden Delphi-Quelltext
1:
2:
// ab in den nächsten Ordner
res  := FindFirst('*.*',faAnyFile,ds);

kannst du mal durch
ausblenden Delphi-Quelltext
1:
res  := FindFirst('*.*',faDirectory { <-- !},ds);					

ersetzen.

Die Idee mit der Auswahl- bzw. Ausschussliste finde ich übrigens gut. Wenn du die Funktion fertig und getestet hast, dann biete sie doch dem Forum als Ergänzung zu dem bisherigen FAQ-Beitrag zum Thema "Dateien suchen" an!

Gruß.