![]() |
Datei suchen u. Path dann in die Registry schreiben
Hi Leute,
Ich hab ein kleines Formular erstellt, mit den Buttons: Suchen, Aktualisieren und Beenden. Weiters habe ich noch ein Label mit den Namen "Pfad" drinn. Wie kann ich es machen damit, wenn ich auf Suchen gehe, im Label dann der genaue Pfad drinn steht, wo die Datei liegt. Ich möchte aber nicht die Datei eingeben, nach der gesucht wird, denn diese Datei hat einen Fixen Namen "Kundendaten.mdb". Es soll einfach nach dieser Datei im "ARBEITSPLATZ" gesucht werden. Es ist doch so, dass dann die ganzen Festplatten automatisch durchsucht werden. Das Ergebnis soll dann im Label ersichtlich sein. Sollte die Datei nicht gefunden werden, so soll eine Messagebox erscheinen wo dann drinn steht: "Leider konnte die Datenbank auf Ihrem PC nicht gefunden werden". Beim Button "Aktualisieren" soll dann der Path der in der Label steht dann in die Registry unter HKEY_CURRENT_USER\Software\AriusDB\SettingsDB gespeichert werden. Kann mir da jemand helfen? |
Re: Datei suchen u. Paht dann in die Registry schreiben
Zitat:
Zitat:
Zitat:
|
Hier ein kleines Tut über die Arbeit mit der Registry 1:1 aus dem EDH
Zitat:
|
Zitat:
Außerdem hat m-werk in AUQ.de bereits geschrieben, dass er die Registry-Sache wahrscheinlich auch allein hinbekommt. Nur mit dem Suchen der Datei hat er Probleme. |
Zitat:
|
Danke. Luckie.
|
Ich bin auch kein Hellseher. Und wenn ich z.B. eine Frage habe, dann poste ich sie nicht gleichzeitig in mehreren Foren. Ich frage erst mal in einem Forum, und wenn ich dann in - sagen wir mal - einer Woche keine Antwort habe, dann wende ich mich an das nächste.
Oder (wenn es so dringend ist, dass ich doch in zwei Foren gleichzeitig frage) ich informiere die Leute in beiden Foren über den Stand der Dinge. Damit halt alle wissen, dass ich Problem A bereits gelöst habe und nun noch eine Lösung für Problem B brauche. Das gehört IMHO zu den viel (und gern auch falsch) zitierten Netiquetten und verhindert, dass die interessierten Helfenden zu Hellsehern oder "regelmäßigen Kontrolleuren" mutieren müssen. :idea: Außerdem verhindert es Zornesausbrüche, wenn sich jemand die Arbeit macht und dem Fragenden eine adäquate Lösung schreibt, die dieser dann mit den Worten "Ach, ich hab´ schon was aus einem anderen Forum" quittiert. Aber bei mir ist es in der Tat so, dass bei einem Online-Ausflug auch automatisch 3 Browserfenster mit Foren zu sehen sind: die Delphi-Praxis, das Entwickler-Forum und auch ![]() |
Hi!
Der grund, warum ich diesen Beitrag in 2 Foren gestellt habe ist der, dass das Tool schon dringenst benötigt wird. Ich komm mit dem Suchen der Datei nicht klar. Ich hab wirklich keine Ahnung, wie ich das mache. Ich habe mir mal die Hilfe angesehen und nach FindFirst usw. gesucht. Ich hab auch was gefunden, aber ich komm nicht dahinter, wie ich Daten suchen kann. Darum bitte ich um eure hilfe! |
Zitat:
|
@MathiasSimmack: Hier in der Delphi-PRAXiS wäre Deine Suchfunktion schon nicht schlecht aufgehoben... :wink:
Grüße, Daniel |
Wirklich? Ich kam mir schon so ausgeschlossen vor:
Zitat:
Also, m-werk - Mein Vorschlag wäre, dass du die eigentliche Suchroutine in eine eigene Prozedur einklammerst. Das ist der beste Weg, da sich diese Prozedur für jedes Unterverzeichnis wieder selbst aufrufen muss. Schließlich willst du ja nicht nur das Hauptverzeichnis C:\ sondern auch C:\Programme usw. durchsuchen?! Ich schlage vor, dass du dieser Prozedur den Root-Pfad immer mit übergibst und diesen Wert nie änderst. Das passiert natürlich programmtechnisch und würde z.B. (s. for-Schleife in meinem letzten AUQ-Posting) so aussehen:
Code:
In der Suchprozedur stellst du dann als erstes fest, wie das aktuelle Verzeichnis heißt, und in der letzten Zeile der Funktion vergleichst du das aktuelle Verzeichnis mit dem übergebenen Root-Pfad. Sind sie unterschiedlich, springst du wieder eine Ebene nach oben.
for i := 2 to 25 do
// Laufwerk muss existieren und dem // gewünschten Typ entsprechen if(DriveExists(i)) and (IsHD(i)) then // es muss möglich sein, auf das Laufwerk // zu wechseln if(SetCurrentDir(CHR(i + BYTE('A')) + ':\')) then begin // rekursive Suchfunktion aufrufen scanit(CHR(i + BYTE('A')) + ':\'); // die Suche abbrechen, wenn die Datei // gefunden wurde if(found) then break; end; Wozu? Das hat mit der Funktion an sich zu tun. Deine Suche startet z.B. in C:\, und die Funktion findet jetzt z.B. das Programme-Verzeichnis. Also wechselt sie in diesen Ordner und ruft sich selbst wieder auf, um die Suche fortzusetzen. Jetzt mal angenommen, es gäbe keine Unterordner mehr. Wenn die Funktion die gesuchte Datei nicht findet, steckt sie im Programme-Ordner fest, und die Suche würde nicht mehr weitergehen, bzw. keine Ergebnisse mehr liefern. Du musst also wieder eine Ebene nach oben ins Hauptverzeichnis C:\ springen, damit dann z.B. der Windows-Ordner gefunden und durchsucht werden kann. usw. usw.
Code:
Nun zur Suche. Grundlegend kann (!) eine FindFirst/FindNext-Suche so aussehen:
procedure scanit(orgPath: string);
var path : string; begin path := GetCurrentDir; // Suchfunktion // kommt gleich, und muss HIER REIN!!! if(Path <> orgPath) then ChDir('..'); end;
Code:
Es gibt auch noch andere Varianten mit repeat-until, aber ich persönlich benutze seit vergangenen TurboPASCAL-Tagen diese while-Konstruktion.
var
res : integer; ds : TSearchRec; begin res := FindFirst('*.*',faAnyFile,ds); while(res = 0) do begin // Anzeige des aktuellen Dateinamens/Verzeichnisses // im Label der Form Form1.Label1.Caption := path + '\' + ds.Name; // ist der Dateiname mit dem Suchnamen identisch? if(lowercase(ds.Name) = lowercase(szSearchFile)) and (ds.Attr and faDirectory = 0) then begin // Ja! Found := true; end // Nein, es ist aber ein Unterverzeichnis. // Also, rein da, & weitersuchen! else if(ds.Attr and faDirectory <> 0) and (ds.Name <> '.') and (ds.Name <> '..') then begin SetCurrentDir(ds.Name); scanit(orgPath); end; // die Suche ist beendet! if(Found) then break; res := FindNext(ds); end; FindClose(ds); {mal empfehlenswert ->} Application.ProcessMessages; end; Du siehst hier auch gleich meine Bool-Variable. Wenn sie auf TRUE gesetzt wird, wird die Schleife verlassen. Logisch! Die Datei wurde ja gefunden, jede weitere Suche wäre Zeitverschwendung. Du solltest wirklich auch break verwenden, damit FindClose in jedem Fall aufgerufen wird. exit wäre zum Verlassen der Schleife zwar möglich, aber nicht empfehlenswert. Übrigens darf die Bool-Variable keine lokale Variable der Prozedur "scanit" sein! Übrigens, schöner Nebeneffekt: bei mir benötigte die Funktion beim ersten Durchlauf ca. 10 Sekunden, um auf einem Athlon mit 1GHz die Laufwerke C-H mit insgesamt 26.685 Dateien und 2.206 Ordnern zu durchsuchen. (Ich habe extra mal nach einem Programm auf der H-Partition suchen lassen!) Das Ganze scheint irgendwie und irgendwo gecacht zu werden, denn jeder weitere Durchlauf benötigte nur noch ca 1.6 Sekunden. Gruß, Mathias. |
Danke für die ausführliche beschreibung. Ich hab nur ein kleines Problem damit.
In welche Procedure setze ich den 1. und den 3. Code? Ich habe den 3 Code in den Button 'Suchen' gesetzt. Ich bin mir aber nicht sicher, ob das auch richtig ist. |
Also ich habe eine Funktion geschrieben, die "Suchen" heißt und so deklariert ist:
Code:
In dieser ... hm, eigentlich ist´s ja eine: Prozedur stecken die Routinen
procedure Suchen(const szSearchFile: string);
Code:
Und du rufst bei deinem Suchen-Button nur diese Funktion auf:
procedure Suchen(const szSearchFile: string);
var Found : boolean; iFiles, iFolders : integer; function DriveExists(DriveByte: Byte): Boolean; begin Result := GetLogicalDrives and (1 shl DriveByte) <> 0; end; function IsHD(DriveByte: Byte): boolean; begin case GetDriveType(pchar(CHR(DriveByte + BYTE('A')) + ':\')) of // Festplatten DRIVE_FIXED, // gemappte Netzlaufwerke DRIVE_REMOTE, // CD-ROM-Laufwerke DRIVE_CDROM: Result := true; else Result := false; end; end; procedure scanit(orgPath: string); var path : string; res : integer; ds : TSearchRec; begin path := GetCurrentDir; res := FindFirst('*.*',faAnyFile,ds); while(res = 0) do begin // Anzeige des aktuellen Dateinamens/Verzeichnisses // im Label der Form Form1.Label1.Caption := path + '\' + ds.Name; // ist der Dateiname mit dem Suchnamen identisch? if(ds.Attr and faDirectory = 0) then begin inc(iFiles); if(lowercase(ds.Name) = lowercase(szSearchFile)) then Found := true; end // Nein, es ist aber ein Unterverzeichnis. // Also, rein da, & weitersuchen! else if(ds.Attr and faDirectory <> 0) and (ds.Name <> '.') and (ds.Name <> '..') then begin inc(iFolders); SetCurrentDir(ds.Name); scanit(orgPath); end; // die Suche ist beendet! if(Found) then break; res := FindNext(ds); end; FindClose(ds); Application.ProcessMessages; if(path <> orgPath) then ChDir('..'); end; var i : integer; dwTime : dword; begin found := false; iFiles := 0; iFolders := 0; Screen.Cursor := crHourglass; dwTime := GetTickCount; // da üblicherweise die Buchstaben A & B für Disketten // reserviert sind, kann die Schleife bei C beginnen // 2 + 65 (ASCII-Code für A) = 67 (ASCII-Code für C) for i := 2 to 25 do // Laufwerk muss existieren und dem // gewünschten Typ entsprechen if(DriveExists(i)) and (IsHD(i)) then // es muss möglich sein, auf das Laufwerk // zu wechseln if(SetCurrentDir(CHR(i + BYTE('A')) + ':\')) then begin // rekursive Suchfunktion aufrufen scanit(CHR(i + BYTE('A')) + ':\'); // die Suche abbrechen, wenn die Datei // gefunden wurde if(found) then break; end; dwTime := GetTickCount - dwTime; Form1.Label2.Caption := inttostr(dwTime) + ' msec'; Form1.Label3.Caption := inttostr(iFiles) + ' Dateien, ' + inttostr(iFolders) + ' Ordner durchsucht'; Screen.Cursor := crDefault; // nichts gefunden, Label leeren if(not(found)) then Form1.Label1.Caption := ''; Form1.Button2.Enabled := found; end;
Code:
Ich habe noch drei Labels. Label1 ist das, wo bei dir dann wohl auch der Name angezeigt werden soll. Die beiden anderen sind nur zur Anzeige der Zeit und der Anzahl der Dateien/Ordner, weil ich halt wissen wollte, wie lange das dauert.
procedure TForm1.Button1Click(Sender: TObject);
begin Suchen('Kundendaten.mdb'); end; |
Hi, vielen Dank für deine bemühungen.
Code:
Bei diesem Code kommen folgende Fehlermeldungen:
procedure TForm1.SuchenClick(Sender: TObject);
begin Suchen('Kundendaten.mdb'); end; Bei 'Suchen(' steht der Cursor nach der Klammer und die fehlermeldung lautet: Operator oder Semikolon fehlt Und zum Schluss dieser Zeile 'Anweisung erforderlich, aber Ausdruck vom Typ 'TButton' gefunden' Ich habe dann bei 'Suchen:=('Kundendaten.....' eingegeben Nun kommt nur mehr eine Meldung: [Fehler] DBsuche.pas(171): Inkompatible Typen: 'TButton' und 'String' Mit dieser kann ich leider nichts anfangen |
Zitat:
Code:
Da ich ja nicht wissen konnte, wie du deinen Button nennst, habe ich meiner Funktionen einen recht eindeutigen Namen gegeben, der nun -sinnigerweise- mit dem deines Buttons identisch ist. Also kommen sich beide in die Quere.
// Der Button, auf den du klickst, heißt "Suchen"
procedure TForm1.SuchenClick(Sender: TObject); begin // Die Funktion, die du aufrufst, heißt AUCH "Suchen" Suchen('Kundendaten.mdb'); end; Zwei Möglichkeiten:
|
Hi, danke, das mit dem Suchen funktioniert jetzt prima.
Ich hab nur noch ein kleines anliegen. Wenn ich jetzt auf Aktualisieren klicke, dann wird jetzt der Wert, der im Label steht richtig in die Registry geschrieben. Dabei ist mir jetzt eines aufgefallen. Im Label steht z.B. C:\Arius\Datenbank\Kundendaten.mdb Wenn ich jetzt den Label in die Registry hineinstelle, dann steht dort auch der Wert C:\Arius\Datenbank\Kundendaten.mdb Ich möchte aber jetzt nur in der Registry stehen haben C:\Arius\Datenbank Wie kann ich das jetzt noch machen, dass die Datei nicht mit übernommen wird? |
Hallo m-werk,
dazu gibt es die Funktion:
Code:
diese gibt als Ergebnis nur den Pfad zurück, der in FileName enthalten ist.
function ExtractFilePath(const FileName: string): string;
|
Hi, und wo baue ich diesen code ein?
Zum Aktualisieren sieht mein Code so aus:
Code:
procedure TForm1.AktualisierenClick(Sender: TObject);
var REG:TRegistry; b:string; begin b:=Form1.Label4.Caption; REG:=TRegistry.Create; try REG.RootKey := HKEY_CURRENT_USER; if REG.OpenKey('Software\AriusDB\SettingsDB', True) then begin REG.WriteString('DBPath', b); end; finally REG.CloseKey; REG.Free; end; end; |
Hallo m-werk,
Code:
oder
...
begin b:=Form1.Label4.Caption; REG:=TRegistry.Create; try REG.RootKey := HKEY_CURRENT_USER; if REG.OpenKey('Software\AriusDB\SettingsDB', True) then begin REG.WriteString('DBPath', ExtractFilePath(b)); end; finally REG.CloseKey; REG.Free; end; end;
Code:
Dabei sollte aber sicher gestellt sein, dass Label4 immer einen gültigen Dateinamen (inkl. Pfad) enthält.
...
begin b:=ExtractFilePath(Form1.Label4.Caption); REG:=TRegistry.Create; try REG.RootKey := HKEY_CURRENT_USER; if REG.OpenKey('Software\AriusDB\SettingsDB', True) then begin REG.WriteString('DBPath', b); end; finally REG.CloseKey; REG.Free; end; end; |
Hi, danke und was ist jetzt mit dieser Funktion:
Code:
Benötige ich diese auch noch? Wenn ja, wo setze ich diese hinein?
function ExtractFilePath(const FileName: string): string;
|
Hallo m-werk,
das war nur die Deklaration aus der Unit SysUtils. Wenn du also
Code:
in deiner Anwendung verwendest, kannst du die Codebeispiele problemlos übersetzen. Dort habe ich ja den Aufruf eingebaut.
uses SysUtils
|
Hi, ich danke dir für die Hilfe.
Jetzt funktioniert alles. |
Hi, ich danke dir für die Hilfe.
Jetzt funktioniert alles. Eine Sache habe ich da aber noch. Ich habe in dieser Form auch ein Infofenster mit einem Label drinn. In diesem Label wird mir angezeigt, wo die Datenbank liegen soll, wenn schon in der Registry ein eintrag vorhanden ist. Im Anderen Label (Label4) wird mir der Pfad der Datenbank angezeigt, wo wirklich die Datenbank dann ist. Es kann jetzt so sein, dass die beiden Pfade, von Label 1 und Label 4 gleich sind. Ich möchte eine überprüfung nach dem Suchen starten. Wenn Label1 = Label4 dann soll der Button 'Aktualisieren.Enabled := False' sein. Wie kann ich noch diese Überprüfung in meinem Suchen Button einbauen? Es soll aber wieder nur der Pfad und nicht mit der Datei überprüft werden! |
Hallo m-werk,
der Code dazu wäre:
Code:
Du musst aber noch die korrekte Stelle finden, an der diese Anweisung eingefügt werden soll. Es muss eine Stelle sein, an der sowohl Label1 als auch Label4 ihre Werte korrekt anzeigen.
Aktualisieren.Enabled := (ExtractFilePath(Label1.Caption) = ExtractFilePath(Label4.Caption));
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz