Entwickler-Ecke
Dateizugriff - Rekursives Suchen mit Ausschlussliste [gelöst]
lambruco - Mi 16.07.03 11:02
Titel: Rekursives Suchen mit Ausschlussliste [gelöst]
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.
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 < 0) or 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); 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
UGrohne: Code- durch Delphi-Tags ersetzt
GruppeCN - Sa 19.07.03 16:15
Laut Titel ist dein Problem gelöst. :lol: Vielleicht postest du mal den richtigen Code, die Lösung, ...
Delete - 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:
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:
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'; procedure FindFiles(const orgpath: string; const FindMask: TStringList; ResultPath, ResultDateTime, ResultFiles: TStrings); var path : string; res : integer; ds : TSearchRec; iAge : integer; begin if(FindMask = nil) or (FindMask.Count = 0) or (ResultPath = nil) or (ResultDateTime = nil) or (ResultFiles = nil) then exit;
path := GetCurrentDir;
res := FindFirst('*.*',faAnyFile,ds); while(res = 0) do begin if(ds.Attr and faDirectory = 0) and (ds.Name <> '.') and (ds.Name <> '..') then if(FindMask.IndexOf(ExtractFileExt(ds.Name)) = -1) then begin ResultPath.Add(path);
iAge := FileAge(path + '\' + ds.Name); if(iAge <> -1) then ResultDateTime.Add(FormatDateTime('' , FileDateToDateTime(iAge))) else ResultDateTime.Add('-unbekannt-');
ResultFiles.Add(ds.Name); end;
res := FindNext(ds); end; FindClose(ds);
res := FindFirst('*.*',faAnyFile,ds); while(res = 0) do begin if(ds.Attr and faDirectory <> 0) and (ds.Name <> '.') and (ds.Name <> '..') then begin ChDir (ds.Name); FindFiles(orgPath, FindMask, ResultPath, ResultDateTime, ResultFiles); end;
res := FindNext(ds); end; FindClose(ds);
if(path <> orgpath) then ChDir('..'); end; |
Anwendungsbeispiel:
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 <> nil) then 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 - 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
Delete - 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.
Delete - 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
Delphi-Quelltext
1: 2:
| procedure FindFiles(const orgpath: string; const 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:
Delphi-Quelltext
1: 2: 3: 4: 5:
| 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 and faDirectory = 0) then |
und
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 <> 0) Then |
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:
Delphi-Quelltext
1:
| if(cnt = 0) then 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 - 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
Delete - 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)
Delphi-Quelltext
1: 2:
| res := FindFirst('*.*',faAnyFile,ds); |
kannst du mal durch
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ß.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!