Autor Beitrag
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 24.09.05 14:56 
Für das Gemeinschaftsprojekt [url=www.killprocess.de.vu]Killprocess[/url], in dem ich bin, benötigten wir ein schnelles Suchverfahren um Musikdateien für den MP3-Tag-Editor zu finden. Angefangen haben wir mit dem wohl bekanntesten aber langsamen SearchRec, danach fand ich die Unit DriveTools von Luckie, wesentlich schnellern war. Da darauf jedoch ein Copyright ist ;) und ich im Projekt so wenig wie möglich externes haben möchte, habe ich mir die Arbeit gemacht, diese Unit umzuschreiben (aber nur die Prozeduren, die ich brauchte). Herausgekommen ist die Unit SearchTools, die einiges dem Programmierer im Vergleich zu der Unit DriveTools vereinfacht, dafür aber einiges nicht bietet, was die Luckies Unit besitzt. So gibt es die Prozedure GetLogicalDrives und die Funktion GetVolumeLabel nicht (dafür kann man ja dann die DT nehmen ;) ). Ich muss aber dazu sagen, das die Prozedur GetLogicalDrives indirekt eingebaut ist. Sprich wenn man als Root den Arbeitsplatz angibt und Rekursiv sucht, sucht er gleich alle Laufwerke ab, wodurch ich auch nach den Laufwerken suchen musste.

Features
enthaltene Features
Auflistung folgt später

geplante Features
  • Suche nach Dateien bestimmtes Alters (letzte Änderung etc.) muss noch die Unterschiede zwischen FAT und NTFS raussuchen, denn soweit ich MSDN bsiher verstanden habe sind die Zeitformate verschieden
  • (Auslagerung in DLL und diese) ASM-optimieren, sprich das ASM-Code beim Aufruf erzeugt wird, der dann erst ausgeführt wird (spart unnötiges Abfragen und Konfigurationen seitens der User) Machbarkeitsstudie noch erforderlich, ob Virenscanner etc. da ein problem haben


abgelehnte Features
  • Linux-Version Da die Unit fast nur aus WinAPI besteht, käme eine Kompatibilität zu Linux einer extra Unit gleich


Programme die diese Unit verwenden


//EDIT: Versionsänderungen heruasgenommen (im Source enthalten)
Einloggen, um Attachments anzusehen!


Zuletzt bearbeitet von Heiko am Fr 26.10.07 20:14, insgesamt 18-mal bearbeitet
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.09.05 16:43 
ausblenden Delphi-Quelltext
1:
if FileName='Arbeitsplatz\' then					

Viel Spass auf Rechnern mit nicht deutschen Windows. ;)

Aber wenn deine Unit schon auf meiner basiert, dann wäre es auch nett, wenn ich zu mindest im Dateiheader erwähnt würde mit mit Verweis auf die ursprüngliche Unit. BTW gibt es eine neue Unit DriveTools: MpuDriveTools mit einer Klasse die den Fortschritt beim Suchen der Dateien anzeigt: www.luckie-online.de...er/Delphi/Sonstiges/
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 24.09.05 16:51 
Gut das du mich daran erinnerst. Das mit dem Arbeitsplatz wollte ich noch verbessern (habe ich glatt vergessen ;) ). Ein kommentar das es aus der Unit abgeleitet ist kann ich noch hinzufügen (hatte ich nicht gemacht, da doch eine starke Abweichung vorhanden ist).

@MpuDriveTools: Die habe ich schon gesehen, allerdings nützt das mit dem Fortschritssbalken mir nix, da es ein zu großer Performanceverlust bedeutet (wenn ich das machen würde, wäre ich wieder bei der gleichen Performance wie deiner, da ich erst alle ordner suchen müsste). Und beim Projekt, wofür es ja ist, haben wir dafür einen Fortschrittsbalken zum Auslesen von DateiInfos verwendet, da es dort kein (großer) Performanceverlust ist, wenn man noch eine Gauge auf Minimalbetrieb mitbetreibt. Während der Suche mit dem SearchTool habe ich einen endlosen Progressbar genommen, damit man nicht das Gefühl bekommt, das er nix macht, wenn man die festplattenauslastung nicht sieht.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.09.05 17:03 
user profile iconHeiko hat folgendes geschrieben:
Ein kommentar das es aus der Unit abgeleitet ist kann ich noch hinzufügen (hatte ich nicht gemacht, da doch eine starke Abweichung vorhanden ist).

Ich habe ja auch geschrieben "wäre nett", aber kein muss. Denn immerhin habe ich teilweise meinen Variablen und Prozedurnamen wieder erkannt. ;)

Zitat:

@MpuDriveTools: Die habe ich schon gesehen, allerdings nützt das mit dem Fortschritssbalken mir nix, da es ein zu großer Performanceverlust bedeutet (wenn ich das machen würde, wäre ich wieder bei der gleichen Performance wie deiner, da ich erst alle ordner suchen müsste). Und beim Projekt, wofür es ja ist, haben wir dafür einen Fortschrittsbalken zum Auslesen von DateiInfos verwendet, da es dort kein (großer) Performanceverlust ist, wenn man noch eine Gauge auf Minimalbetrieb mitbetreibt. Während der Suche mit dem SearchTool habe ich einen endlosen Progressbar genommen, damit man nicht das Gefühl bekommt, das er nix macht, wenn man die festplattenauslastung nicht sieht.

Man muss den Fortschritt ja nicht nutzen. Desweiteren bin ich hab eich auch nicht mehr das globale Datei Array drinne, was vorher noch sehr unschön war.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 24.09.05 17:17 
user profile iconLuckie hat folgendes geschrieben:
user profile iconHeiko hat folgendes geschrieben:
Ein kommentar das es aus der Unit abgeleitet ist kann ich noch hinzufügen (hatte ich nicht gemacht, da doch eine starke Abweichung vorhanden ist).

Ich habe ja auch geschrieben "wäre nett", aber kein muss. Denn immerhin habe ich teilweise meinen Variablen und Prozedurnamen wieder erkannt. ;)

In der version auf meinem PC ist es jetzt dabei, damit man weiß das es deine gibt mit Funktionen, die bei mir nicht drin sind ;).
@Dateinamen: Die meisten habe ich gelassen, da sie schon passend benannt sind und ich einige genau gleich benannt hätte, wie wfd für TWin32FindData ;) (bei zu langen Typen und Namen die ich nicht zufällig so ähnlich drin habe mache ich das manchmal so).


user profile iconLuckie hat folgendes geschrieben:
user profile iconHeiko hat folgendes geschrieben:
@MpuDriveTools: Die habe ich schon gesehen, allerdings nützt das mit dem Fortschritssbalken mir nix, da es ein zu großer Performanceverlust bedeutet (wenn ich das machen würde, wäre ich wieder bei der gleichen Performance wie deiner, da ich erst alle ordner suchen müsste). Und beim Projekt, wofür es ja ist, haben wir dafür einen Fortschrittsbalken zum Auslesen von DateiInfos verwendet, da es dort kein (großer) Performanceverlust ist, wenn man noch eine Gauge auf Minimalbetrieb mitbetreibt. Während der Suche mit dem SearchTool habe ich einen endlosen Progressbar genommen, damit man nicht das Gefühl bekommt, das er nix macht, wenn man die festplattenauslastung nicht sieht.

Man muss den Fortschritt ja nicht nutzen. Desweiteren bin ich hab eich auch nicht mehr das globale Datei Array drinne, was vorher noch sehr unschön war.

Wenn man den nicht nutzt, bringt einem die Unit MpuDriveTools nix, denn dann kann man ja gleich die Unit DT nehmen.
@Globale Variable: Habe ich mit Absicht gelassen, obwohl ich retnyg's Kommentar gelesen habe, damit ich später wieder auf das ausgelesene Zurücklgreifen kann, ohne es etxra zwischenzuspeichern.

PS: Bei Namen nehme ich das ' rein, damit man den Namen vom Fall abgetrennt erkennt ;).
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.09.05 17:20 
user profile iconHeiko hat folgendes geschrieben:

Wenn man den nicht nutzt, bringt einem die Unit MpuDriveTools nix, denn dann kann man ja gleich die Unit DT nehmen.

Doch, es ist OOP konform und somit einfach sauberer.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 24.09.05 17:32 
Warum sauberer? Wenn man etwas nicht benötigt (in dem Fall die OOP) und nicht braucht nenne ich das nicht sauberer.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 24.09.05 18:37 
Die globale Variable bleibt unsauber und hier ist sie sogar gefährlich, wenn man vergisst sie zu initialisieren. Und das ist keine Frage von brauchen oder nicht brauchen. Und was hat brauchen oder nicht brauchen damit zu tun, ob namn den Cpde sauber in eine Klasse verpackt oder nicht?
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 24.09.05 20:06 
Wenn man vergisst sie zu initialisieren ist bei meiner Version egal, da er es bei jedem Aufruf selber macht. Und wenn man sie als Parameter übergibt, muss der Programmierer ja schließlich auch dafür sorgen, das sie initialisiert wird, wenn er sie sich global speichert um damit längere Zeit arbeiten zu können.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 22.10.05 14:11 
So, ich habe jetzt die neue Version fertig (nach dem sie seit einem Tag nach der Veröffentlichung der Version 1 sich in der Beta-Phase befand). Die Neuerungen habe ich oben im ersten Post hingeschrieben.

Hier ist auch meine Performance-Vergleich-Prozedur, damit ihr seht das es ein fairer Vergleich ist ;):

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:
procedure TForm1.Button4Click(Sender: TObject);
var
  StringArray: TStringArray;
  i: Integer;
  Zeit1, Zeit2, StartZeit: Cardinal;
begin
  SetLength(StringArray, 1);
  StringArray[0]:='*.mp3';
  for i:=0 to 1 do
  begin
    SearchTool.SearchFiles('C:\', StringArray, true);
    DriveTools.InitFindAllFiles;
    DriveTools.FindAllFiles('C:\''*.mp3', true);
  end;
  Zeit1:=0;
  Zeit2:=0;
  for i:=0 to 1 do
  begin
    StartZeit:=GetCurrentTime;
    SearchTool.SearchFiles('C:\', StringArray, true);
    inc(Zeit1, GetCurrentTime-StartZeit);

    StartZeit:=GetCurrentTime;
    DriveTools.InitFindAllFiles;
    DriveTools.FindAllFiles('C:\''*.mp3', true);
    inc(Zeit2, GetCurrentTime-StartZeit);
  end;
  ShowMessage('ST: '+IntToStr(Zeit1 div 2)+' ms'+#13+
              'gefundene Dateien: '+IntToStr(SearchTool.cntFoundFiles)+#13+
              'DT: '+IntToStr(Zeit2 div 2)+' ms'+#13+
              'gefundene Dateien: '+IntToStr(DriveTools.cntFoundFiles));
end;
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 22.10.05 15:02 
Wie schon im andren Thread geschrieben, es gibt eine neue version: www.luckie-online.de...er/Delphi/Sonstiges/ -> MpuDriveTools.pas
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Sa 22.10.05 15:22 
Titel: Re: SearchTool - schnelles Suchverfahren
user profile iconHeiko hat folgendes geschrieben:
... Da darauf jedoch ein Copyright ist ;) und ich im Projekt so wenig wie möglich externes haben möchte, habe ich mir die Arbeit gemacht, diese Unit umzuschreiben (aber nur die Prozeduren, die ich brauchte). Herausgekommen ist die Unit SearchTools, ...

Es geht mich ja eigentlich Nichts an, aber ...
Du kopierst, gibst es auch zu und meinst dann auch, Du wärst gnädig, wenn Du einen Verweis auf den ursprünglichen Programmierer nach dessen Bitten in deiner SW unterbringst. Wow, Echt Klasse. Mit anderen Worten: Du bist nicht selbst drauf gekommen, kopierst schamlos und meinst dann auch noch, es wäre dein geistiges Eigentum. Ich nenn soetwas eine bodenlose Frechheit.

Heiko, Du hast dich gerade in meinen Augen selbst disqualifiziert.

Denk mal drüber nach.

_________________
Na denn, dann. Bis dann, denn.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Sa 22.10.05 18:44 
Jein, das mit dem geistigen Eigentum ist eine zwiespaltige Angelegenheit. Denn ich habe mir bei Luckie die Variante mit dem Suchen abgeguckt, denn meine alte Variante mit SearchRec war echt lahmarschig, was ich benutztern von Programmen wo ich mitarbeite nicht antuen will (5 Min. vs. 5 Sek. ist doch ein gravierender Unterschied). Durch Zufall bin ich dann auf Luckies DriveTools hier im Forum gestoßen die ich dann erstmal verwendet habe (ohne groß eine Ahnung zu haben wie die funktioniert). Jedoch habe ich gleich eine Änderung vorgenommen, die ein paar Zeilen spart, da einige Dinge vorsehbar sind, sprich von TWin32FindData, wenn es einen Ordner gefunden hat, cFileName immer ohne "\" endet. Luckie führt jedoch bei der Rekursion immer zu begin eine Überprüfung des Pfades auf "\" als letztes Zeichen auf und wenn es nicht vorhanden ist setzt er es hinzu. Wie er auf den Gedanken kam war mir sofort klar, denn wenn man die Prozedur aufruft kann man das ja vergessen haben. Wenn die jedoch durch die Rekursion aufgerufen wird, kann man ja eigentlich schon gleich das "\" beim Parameter hinzufügen. Für den Fall das der Programmierer den Fehler beim Aufruf macht, kann man einen Fehler durch eine Überprüfung in einer extra Prozedur gestalten, die dann erst den Suchalgorithmus den Suchalgorithums aufruft.
Nach einiger Zeit der Nutzung habe ich mich dann jedoch gefragt wie die genau funktioniert, da ich keine Ahnung hatte wie die funktionieren soll, da ich kein anderes Verfahren als die mit dem SearchRec kannte, so dass ich angefangen habe mich dort reinzudenken. Beim reindenken sind mir dann gewisse Schwachstellen in der Unit aufgefallen, sprich das er bei einer rekursiven Suche einmal nach der Datei sucht mit dem Filter (was Performance mäßig schnell ist), dann jedoch noch einmal nach allen Dateien sucht und diese dann darauf überprüft ob es ein Ordner ist. Das ist jedoch eine doppelte Durchsuchung der Festplatte Suche nach den Dateien.
Damit war der erste Gedanke einer Umschreibung der Unit entstanden. Nach dem ich die Unit zum ersten mal genutzt hatte, habe ich gleich nachgefragt ob man Luckies Unit auch in Freewareprogrammen verwenden darf, woraufhin er es ausdrücklich zusagte. Daraufhin hatte ich gleich noch einmal nachgefragt ob wir ihn auch in die Aboutbox des Programmes erwähnen sollen, auch wenn ich die Unit ein umschreibe. Daraufhin bekam ich jedoch keine Antwort, wodurch ich mir dahcte das wir ihn Sicherheitshalbe aufnehmen werden. Aber ich hatte dabei gleich einen Gedanken dazu bekommen der mir nicht ganz behagte, sprich ich finde es blöd wenn man ein Programm als Freeware anbeitet, wo in der AboutBox dann 5 Leutchen als Entwickler stehen und dann noch ne ganze Stange von Personen, von denen man Units verwendet hat. Das war dann der Ausschlag die Unit fast komplett umzuschreiben.
Allerdings hatte ich dabei ein Problem: Ich hatte kaum Ahnung von Win-API wo ich mit Handles & Co umgehen muss. Dadurch habe ich nicht eine neue Unit erstellt und so aus freien Stücken angefangen zu entwickeln, sondern habe mir seinen Quelltext kopiert und den dann immer Stück für Stück umgeschrieben, so dass ich immer überprüfen konnte ob sie noch funktioniert (bloß gut, denn manchaml hatte ich dann einen kleinen Denkfehler drin, den ich so schnell gefunden habe).
Dann stand die Unit erstmal, mit noch ein ganz paar Resten von Luckies Quelltext. Da es jedoch für eine Gruppenarbeit ist, habe ich mir dann gedacht gehabt, das ich alles was mit der Suche in die Unit auslaggere, sprich die Überprüfung ob ich überhaupt auf das Laufwerk zugreigen kann und die Suche nach allen Laufwerke bei Übergabe des Arbeitsplatzes,. Und da ich ja sowieso schon eine Prozedur hatte die aufgerufen wird bevor der Suchalgorithmus gestartet wird, konnte ich es ohne Probleme dort einfügen. Dazu kam später die Überprüfung ob der Ordner überhaupt existiert, in dem die Suche gestartet werden soll.
Allerdings gab es dann immernoch eine Stelle dir mir nicht gefallen hat. Und zwar das ich die Prozedur oft hintereinander aufrufen muss, da ich ja nach bis zu 7 Formaten mit einmal suchen will. So habe ich mich nochmal ans Werk gemacht und die Unit weiterumgeschrieben, das er jede Datei gleich auf die Endung überprüft ob die in der Liste steht. So ungefähr war der Verlauf zur v1.0 von der SearchTool.
Als die fertig war habe ich auch gleich BenBE gefragt, ob wir die Unit irgendwie für Omorphia verwenden können, wo er zusagte. Da jedoch eine Suche nur auf Endungen nicht so güstig ist, schrieb ich gleich an einem Filter, der auch Suche mit Sternchen erlaubt und auch genaue Dateinamen. Damit war ich innerhalb von ein paar Stunden fertig, wo viel Zeit im testen Verging - und in der Fehlersuche ;).
Nachdem das funktioniert hat, hatte ich überlegt, ob ich es als v2.0 veröffentliche. In der Zeit hat jedoch schon Luckie mich darauf hingewiesen das die Überprüfung auf Arbeitsplatz nur auf deutschen Windows-Versionen funktioniert, so dass ich die v2.0 doch nicht verlöffentlichte und sie erstmal in den Beta-Status wieder schob. Dann begann die Große Suche nach einer Möglichkeit den "Fehler" auszubessern, jedoch mit keinem Ergebnis was mir so schnell half. In zwischen habe ich es hinbekommen.

Durch den Verlauf entstand erstmal eine so ziemlich vollständige Fehlerbehandlung, aber auch ein Quelltext der inzwischen 275 Zeilen lang ist. Luckies ist jedoch nur 209 Zeilen lang, obwohl er Funktionen anbietet dich ich nicht verwendet habe. Des weiteren kam dazu das ich beim Umschreiben eine ganze Menge ein bisschen anders gelöst habe. Dadurch sind es schätzungsweise noch 20-50 Zeilen Quelltext mit Luckies übereinstimmen, da ich keinen Grund sah die umzuschreiben.
Bei den paar Zeilen Übereinstimmung fand ich es nicht nötig Luckie groß noch zu Erwähnen (nach Wunsch von Luckie habe ich es aber hinzugefügt das sie von ihm abgeleitet ist, obwohl so wenig übereinstimmt noch). Durch die paar Zeilen könnte man sagen zwar sagen das es Diebstahl von geistigen Eigentum ist, aber da sich dabei ja eigentlich nur um etwas aufeinander bauendes handelt (die Verwendung von TWin32FindData) empfinde ich es eigentlich nicht als solchen Diebstahl, da ja der Rest eigentlich von mir stammt, wo sich manchmal allerdings einige Passagen verhindern ließen, wo man denken könnte das von Luckie stammt, was aber meistens nicht stimmt.

Ich hoffe du verstehst jetzt meinen Gedankengang alzaimar ;).

mfg
Heiko
alzaimar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2889
Erhaltene Danke: 13

W2000, XP
D6E, BDS2006A, DevExpress
BeitragVerfasst: Sa 22.10.05 20:15 
Dein Gedankengang wird immer klarer :wink:
Du findest es nicht nötig, den Verfasser des Quelltextes, den Du umgeschrieben hast, zu erwähnen? Du nimmst die Idee und den Gehirnschmalz eines Anderen, lernst daraus und entfernst dann das Copyright. Also, das muss nicht sein. Du bist doch dankbar, das jemand wie Luckie Dir seinen Code zur Verfügung gestellt hat. Ohne diesen Code wärst Du mit deinem Tool nicht da, wo Du jetzt bist, oder? Du hast den Code modifiziert und erweitert, aber, es bleibt letztendlich Luckies Verdienst.

Du hast es doch nicht nötig, mit Danksagungen und Copyrighthinweisen zu sparen.

"Basiert auf dem Code von Luckie und Tipps und Tricks des www.delphi.forum.de, Danke an Alle"

So als Tipp.

Na denn, weitermachen :beer:

"Wer sich dankbar zeigt, dem wird auch Dank zuteil"

_________________
Na denn, dann. Bis dann, denn.
retnyg
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2754

SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
BeitragVerfasst: So 23.10.05 06:01 
so, ich habe deine unit mal ausgiebig getestet und mit meiner und luckies verglichen.
also:
- die methode, die ordner nicht separat zu scannen bringt nur was bei *.*
- deine unit unterstützt *.* scheinbar nicht :shock: cntFoundfiles = 0
- deine unit unterstützt keine suche nach dateien wie "*bl*.mp3", "slayer", usw
- deine unit liefert keine verzeichnisnamen (wie bei luckie)
- deine unit hat wie luckie's keine möglichkeit, einen fortschritt anzuzeigen
- dafür kann man mehrere "suchbegriffe" übergeben, und die geschwindigkeit ist ziemlich gut, wenn ein resultat kommt...

hier mal meine version, hab da heute den ganzen tag dran rumgewerkelt o0
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:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
unit retFileSearch;

// ============================================================
// done by retnyg @ http://krazz.net/retnyg
//
// optimized version of luckie's findallfiles in drivetools.pas
//
// new: - no init routine needed
//      - no need to check global variables inside the unit
//      - possibility of adding a callback proc for progress update
//      - optimized much
//      - can return also directories

interface

uses windows;

  type tArray = array of string;
  type tfcbfunc = procedure (x:integer;t:tarray);

  function FindAllFiles(RootFolder: string; Mask: stringvar outputArray: TArray; callback: TFCBFunc; Recurse: Boolean = True; ShowDirectories: boolean = false):integer;

implementation

//function PathMatchSpecA(pszFile, pszSpec: String): Boolean; StdCall; External 'SHLWAPI.DLL';

function FindAllFiles(RootFolder: string; Mask: stringvar outputArray: TArray; callback: TFCBFunc; Recurse: Boolean = True; ShowDirectories: boolean = false):integer;
const
  C_STEP   = 128;            // Get Memory after x array entries
  C_DOT    = $0000002E;     // '.'
  C_DOTDOT = $00002E2E;     // '..'
  C_WILDC1 = '*'//: WORD = $2A5C;  // '\*'
  CC_WILDC = $002A2E2A;
  C_WILDC2 = '*.*';//$002A2E2A;     // '\*.*'
  CC_WILDC2 : word = $002A;
  CC_DIRSUFFIX : word = $005C;

  SIZE_OF_WFD = sizeof(Twin32FindData);

var
  fileCount: integer;
  cRoot: array [1..MAX_PATH] of char;
  bMaskIsWildcard: boolean;
  lMask        : integer;

  procedure ParseDir(idx:integer);
  var
    l : integer;
    hFindFile    : THandle;
    wfd          : TWin32FindData;

    procedure Add;
    begin
      if fileCount mod C_STEP = 0 then setlength(OutputArray, filecount + C_STEP);
      setlength( outputArray[fileCount], idx + l);
      move(cRoot,outputArray[fileCount][1], idx);
      move(wfd.cFileName, outputArray[fileCount][idx+1],l);

      if cardinal(@callback) <> 0 then callback(fileCount,outputarray);
      inc(fileCount);
    end;

    procedure SetMask;
    begin
      move(pointer(Mask)^,cRoot[idx+1],lMask+1); // #0 mitkopieren
    end;

  begin
      if (Recurse) or (bMaskIsWildCard) or (pointer(Mask) = nilthen
        pcardinal(@cRoot[idx+1])^ := CC_WILDC
        //pword(@cRoot[idx+1])^ := CC_WILDC2
      else
        SetMask;

      fillchar(wfd,SIZE_OF_WFD,0);

      if (Recurse and not bMaskIsWildCard) or (pointer(Mask) = nilthen begin
        hFindFile := FindFirstFile(@cRoot, wfd);
        if hFindFile <> INVALID_HANDLE_VALUE then
        repeat
            if wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY = FILE_ATTRIBUTE_DIRECTORY then
            if (pdword(@wfd.cFileName[0])^ <> C_DOT) and
               (pdword(@wfd.cFileName[0])^ <> C_DOTDOT) then
            begin
              l := 0;
              while wfd.cFileName[l] <> #0 do inc(l);
              if ShowDirectories then Add;
              if (pointer(Mask) <> nilor (Recurse) then begin
                move(wfd.cFileName,cRoot[idx + 1],l);
                pword(@cRoot[idx + l + 1])^ := CC_DIRSUFFIX;
                parseDir(idx + l + 1);
              end;
            end;
        until FindNextFile(hFindFile, wfd) = False;
        windows.FindClose(hFindFile);
        if pointer(Mask) <> nil then SetMask;
      end;

      if pointer(mask) <> nil then begin

        hFindFile := FindFirstFile(@cRoot, wfd);
        if hFindFile <> INVALID_HANDLE_VALUE then
        repeat
          l := 0;
          while wfd.cFileName[l] <> #0 do inc(l);
          // die 2 zeilen entsprechen         l := strlen(@wfd.cFileName);
          // sind nun aber inline und unabhängig von sysutils...
          if wfd.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY <> FILE_ATTRIBUTE_DIRECTORY then begin
            //if PathMatchSpecA(string(wfd.cFileName),Mask) then
            Add
          end
          else // isn verz.
            if recurse and bMaskIsWildCard then
              if (pdword(@wfd.cFileName[0])^ <> C_DOT) and (pdword(@wfd.cFileName[0])^ <> C_DOTDOT) then  begin
                if ShowDirectories then Add;
                move(wfd.cFileName,cRoot[idx + 1],l);
                pword(@cRoot[idx + l + 1])^ := CC_DIRSUFFIX;
                parseDir(idx + l + 1);
              end;
        until FindNextFile(hFindFile, wfd) = False
        //else asm int 3 end
        ;
        windows.FindClose(hFindFile);

      end;

      cRoot[idx] := #0;
  end// end proc ParseDir

  var   lRoot: integer;

begin
  fileCount := 0;
  lRoot := length(RootFolder);
  move(pointer(RootFolder)^,cRoot,lRoot+1);
  if cRoot[lRoot] <> '\' then begin
    inc(lRoot);
    cRoot[lRoot] := '\';
    cRoot[lRoot+1] := #0;
  end;
  lMask := length(Mask);
  bMaskIsWildCard := false;
  if lMask = 1 then
    if Mask = C_WILDC1 then
      bMaskIsWildcard := true
    else
  else
    if lMask = 3 then
      if Mask = C_WILDC2 then
        bMaskIsWildcard := true;

  if not (bMaskIsWildCard) and (lMask <> 0then
   if pos(C_WILDC1,Mask) = 0 then begin
     Mask := C_WILDC1 + Mask + C_WILDC1;
     inc(lMask,2);
   end;
  ParseDir(lRoot);
  result := filecount;
  setlength(outputArray, fileCount);
end;



end.

_________________
es gibt leute, die sind genetisch nicht zum programmieren geschaffen.
in der regel haben diese leute die regel...
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 23.10.05 10:27 
user profile iconalzaimar hat folgendes geschrieben:
Ohne diesen Code wärst Du mit deinem Tool nicht da, wo Du jetzt bist, oder?

Ja das stimmt, denn ich kannte die Win-API davor dafür überhaupt nicht.

user profile iconalzaimar hat folgendes geschrieben:
"Basiert auf dem Code von Luckie und Tipps und Tricks des www.delphi.forum.de, Danke an Alle"

Das mit dem Delphi-Forum könnte ich noch hinzufügen, allerdings wäre das sehr verbal. Für das was ich gestern bei der v2.0 noch hinzugefügt habe, habe ich glatt vergessen noch ein paar Personen oben zu benennen, sprich Eugen Honeker und Mathias Simmack, da ich mir dort die Art angeguckt habe um die Bezeichnung für den Arbeitsplatz zu bekommen (alleine hätte ich auch nicht gewusst wie ich das rausbekommen sollte ;) ).

user profile iconretnyg hat folgendes geschrieben:
- die methode, die ordner nicht separat zu scannen bringt nur was bei *.*
- deine unit unterstützt *.* scheinbar nicht :shock: cntFoundfiles = 0
- deine unit unterstützt keine suche nach dateien wie "*bl*.mp3", "slayer", usw

Mhm, da muss ich mal gucken, denn bei mir hat sie funktioniert (muss ich jetzt mal gucken obs immer noch funktioniert ;) ). Aber Danke für den Tipp, werde mal gucken wo es happert.

user profile iconretnyg hat folgendes geschrieben:
- deine unit liefert keine verzeichnisnamen (wie bei luckie)

Wie meinst du das? Das er dir nur Ordner zurückgibt? Das habe ich für die Unit eigentlich nicht gedacht, da ich es für das Projekt nicht brauche, da aber der Filter der in der v2.0 drin ist auch nicht mehr für das ürsprüngliche gemacht ist, kann ich es ja noch einbauen ;).

user profile iconretnyg hat folgendes geschrieben:
- deine unit hat wie luckie's keine möglichkeit, einen fortschritt anzuzeigen

Das ist auch etwas was ich bisher nicht groß benötigt habe, da der Schwerpunkt bei der Fortschrittsanzeige beim MP3-Tag-Editor eigentlich auf das auslesen liegt. Für das normale Suchen habe ich einfach einen durchlaufenden Balken genommen, da die Berechnung für den kurzen Moment ein bisschen auswändiger wäre. Aber ich hatte mir darüber schon einmal Gedanken gemacht. Vlt. baue ich die Idee ja mal ein. ;)

user profile iconretnyg hat folgendes geschrieben:
- dafür kann man mehrere "suchbegriffe" übergeben, und die geschwindigkeit ist ziemlich gut, wenn ein resultat kommt...
Das mit den Resultaten muss ich mal wie gesagt überprüfen, da ich jedoch für mich die v1.0 reicht, ist es mir vlt. nicht aufgefallen das in der v2 ein Fehler sich mal wieder eingeschlichen hat. Aber das mit der Suchgeschwindigkeit war ja mein eigentliches Ziel, denn wie gesagt bei einer Suche 7 Formaten würde ich bei Luckies ein ganzes Stück Geschwindigkeitsverlust haben.
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 23.10.05 10:57 
So Bug behoben. Er trat auf, wenn als letztes Zeichen des Filters ein Sternchen war. Ich hatte einfach vergessen die Klammern zu setzten ;):
ausblenden Delphi-Quelltext
1:
if not ((PosInStr=LenFileName) or Star) then Result:=false;					
retnyg
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2754

SNES, GB, GBA, CPC, A500, 486/66, P4/3.0HT: NintendOS, AmigaOS, DoS
Delphi 5, Delphi 7
BeitragVerfasst: So 23.10.05 16:35 
user profile iconretnyg hat folgendes geschrieben:

- dafür kann man mehrere "suchbegriffe" übergeben, und die geschwindigkeit ist ziemlich gut, wenn ein resultat kommt...

wollte das gerade mal testen mit mehreren suchbegriffen, *.mp3 und *.m3u
deine unit sucht aber nur nach *.mp3
das feature tut also auch nicht ^^
ich habe irgendwie das gefühl, dass du deine eigene unit nicht gerade ausgiebig getestet hast ^^
ausserdem ist die parameterübergabe (mask) in dem array ziemlich unkomfortabel. wie wäre es mit '*.mp3;*.m3u' (die neue version meiner unit machts so) ?

//edit: ausserdem ist die verwaltung der rückgabewerte als globale variable äusserst ungünstig, und disqualifiziert die unit auf anhieb für multithreading

_________________
es gibt leute, die sind genetisch nicht zum programmieren geschaffen.
in der regel haben diese leute die regel...
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 23.10.05 17:40 
Mhm, du scheinst immer irgendwelche Fälle zu haben, die ich nicht teste ;).

@Suchbegriffsübergabe: Könnte man umgestalten, allerdings würde ich dann das | nehmen ;).

@globale Variable für die Rückgabe: Warum disqualifiziert die sich dann dort gleich? Man braucht ja nur den Wert immer in eine andere Variable speichern, wodurch dann paralleles Suchen und auswerten der einzelnen Ergebnisse möglich wäre. Das gleiche würde man ja machen, wenn man parallel Suchen und Auswerten will, wenn man das Array als Parameter übergibt ;).

@Testen: Wie gesagt ich nutzte eigentlich nur v1.0, da ich nur die Endungen brauche, und da gibt es keine Probleme mit Mehrfachfilterung. Es kann eigentlihc nur daran leigen, das ich wahrscheinlich den Filter nur einmal rüberjage anstatt mehrmals ;).
Heiko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: So 23.10.05 18:07 
So, ich habe erstmal den Bug behoben. Der lag nicht daran das der Filter nicht ein 2.x durchlaufen wurde, sondern daran, das ich vergessen habe eine Variable für jeden durchlauf zurückzusetzten. Sprich wenn beim ersten Durchlauf false herauskam, kam nirgendwo mehr eine Stellen, die die Variable für den nächsten Filter wieder auf true setzte.