| Autor |
Beitrag |
lambruco
      
Beiträge: 100
Win 2000/2000 Server/XP
D6 Prof.
|
Verfasst: 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.
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
_________________ Wer Rechtschreibfehler findet, kann Sie behalten
|
|
GruppeCN
      
Beiträge: 322
|
Verfasst: Sa 19.07.03 16:15
Laut Titel ist dein Problem gelöst.  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
|
Verfasst: 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:
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:
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 
|
|
lambruco 
      
Beiträge: 100
Win 2000/2000 Server/XP
D6 Prof.
|
Verfasst: 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
|
Verfasst: 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
|
Verfasst: 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.  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  ), 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 
      
Beiträge: 100
Win 2000/2000 Server/XP
D6 Prof.
|
Verfasst: 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
|
Verfasst: Mo 21.07.03 12:26
| lambruco hat folgendes geschrieben: | | Sehr geehrter Mathias, |
Hm, das ist auch nich´ besser.
| 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ß.
|
|
|