Programmieren - alles kontrollieren 4.941 Themen, 20.708 Beiträge

Delphi 5 - Prozedur für Dateisuche

The_Wise / 7 Antworten / Baumansicht Nickles

Hi !
Ich brauche für ein Programm eine Dateisuche, das mir beispielsweise alle Dateien mit der Endung TXT in einer ListBox anzeigt.
Mein Problem ist, das die Prozedur die ich gemacht habe, nicht alles findet.

Hier die Prozedur:

procedure TMainForm.SearchFile (Pfad: String);
var sr: TSearchRec;
r: Integer;
begin
r:= FindFirst(Pfad + \'\\*.*\', faAnyFile, sr);
while r = 0 do
begin
if Copy(sr.name, 1, 1) \'.\' then
begin
if (sr.attr0) and (faDirectory0) then
SearchFile(Pfad + \'\\\' + sr.name)
else
if Uppercase(System.Copy(sr.name, Pos(\'.\',sr.name), 4)) = \'.TXT\' then
ListBox.Items.Add(Pfad + \'\\\' + sr.name)

end;
Application.ProcessMessages;
r:=FindNext(sr);
end;
FindClose(sr);

end;





Ich verwende rekursive Programmierung. Meinen Fehler habe ich noch nicht entdeckt. Kann mir jemand helfen ?

bei Antwort benachrichtigen
Andreas42 The_Wise „Delphi 5 - Prozedur für Dateisuche“
Optionen

Hi!

Ich hab' im Moment kein Delphi installiert an der Tastatur hängen, aber wenn sich das datei-Attributverarbeiten nicht geändert hat (und wie bei TP geblieben ist), dann ist das Problem deine Erkennung, ob ein Directore gefunden wurde:

if ((sr.attr and faDirectory) = faDirectory) then

sollte die Einträge mit dem Attribut Inhaltsverzeichnis finden.
Da (faDirectory eine Kinstante > 0 ist, ist die Bedingung (faDirectory 0) immer war. Die Prozedur müsste sich also rekursiv starten, wenn ein Dateieintrag mit biliebig gesetzten Attribut gefunden wird.
Deine Prozedur findet bisher IMHO nur Dateien, die kein Attribut gesetzt haben.

Tipp:

Schau dir mal die Funktionen ExtractFileExt() & Co an. Die zerlegen neinen als String übergebenen Pfad mit Dateinamen in die gewünschte Komponente. Soweit ich das sehe, wird deine TXT-Vergleichsfunktion, immer den ersten Punkt im Dateinamen finden finden, dass muss ja mit langen Dateinamen nicht immer der Trenner zum Dateityp sein (wenn ich mich nicht irre).

Ich hoffe, das hilft dir weiter.

Bis denn
Andreas

Hier steht was ueber mein altes Hard- und Softwaregedoens.
bei Antwort benachrichtigen
Borlander The_Wise „Delphi 5 - Prozedur für Dateisuche“
Optionen
procedure TMainForm.SearchFile (Pfad: String);
var
  
sr: TSearchRec;
  r: Integer;
begin
  
r:= FindFirst(Pfad + '\*.*', faAnyFile, sr);
  
while r = 0 do begin
    
//if Copy(sr.name, 1, 1) <> \'.\' then begin
    { Ich gehe davon aus, dass Du damit die Ergebnisse "." & ".." ausschließen
     willst, damit würden alledings auch alle anderen Ergenisse die mit einem
     Punkt beginnen ausgeschlossen.
     Statt mit Copy(String,1,1) solltest Du String[1] verwenden um das erste
     Zeichen zu ermitteln }
    
if (sr.name = '.') or (sr.name = '.') then begin
        
//if (sr.attr<>0) and (faDirectory<>0) then
        { Die 2. Bedingung ist wie schon von Andreas gepostet immmer wahr. Die
erste wird auch in den meisten fällen wahr ergeben, da jede Datei die
verändert wird das Attribut "Archiv" zugewiesen bekommt als Dateien
in die Listbox werden dann natürlich nur die Dateien übernommen die
keine Attribute haben}
        
if (sr.attr and faDirectory) = sr.attr then
          
SearchFile(Pfad + '\' + sr.name)
        
else if Uppercase(ExtractFileExt(sr.Name)) = '.TXT' then
          
ListBox1.Items.Add(Pfad + '\' + sr.name)
    
end;
    Application.ProcessMessages;
    r:=FindNext(sr);
  
end; //while
  
FindClose(sr);
end;

// CU Borlander

bei Antwort benachrichtigen
mr.escape Borlander „ procedure TMainForm.SearchFile Pfad: String var sr: TSearchRec r: Integer begin...“
Optionen

Obgleich ich schon lange kein pascal(delphi) mehr gemacht habe, bin ich aber öfter mit dateisuchfunktionen beschäftigt und kenne einige der tücken (stichwort rekursion und suchmaske).
Davon unabhängig müssten einige codeteile aber anders aussehen:

if (sr.name = '.') or (sr.name = '.') then begin

wird zu
if (sr.name = '.') or (sr.name = '..') then begin

und
if (sr.attr and faDirectory) = sr.attr then

zu
if (sr.attr and faDirectory)  0 then


Meiner meinung nach sollte man auch getrennt nach verzeichnissen und datei suchen, da man dort die suchmasken gleich richtig setzen kann.
D.h.:

suche alle verzeichnisse mit *.* in diesem ordner und rekursiere jeweils hinein
suche danach alle dateien mit *.ext und kehre danach eine ebene zurück

Der grund ist, dass so die dateien eines ordners zusammen bleiben und nicht andere "tiefere" dateien sich in die liste dazwischen mischen.

mr.escape
"The man who trades freedom for security does not deserve nor will he ever receive either." - Benjamin Franklin"Wer seine Freiheit aufgibt, um Sicherheit zu erreichen, wird beides verlieren." - Georg Christoph Lichtenberg
bei Antwort benachrichtigen
Borlander mr.escape „Obgleich ich schon lange kein pascal delphi mehr gemacht habe, bin ich aber...“
Optionen

Da hat sich der Fehlerteufel aber wieder böse bei mir zugeschlagen...

(sr.name = '.') or (sr.name = '..')
Macht anders natürlich keinen Sinn.

(sr.attr and faDirectory) = sr.attr then
Solang die Ordner keine Attribute haben funktioniert das so, um auch die Ordner mit Attributen zu finden ist Andreas Code ((sr.attr and faDirectory) = faDirectory) folglich wesentlich besser geeignet.

0
Dass könnte allerdings bei der Überprüfung von mehreren Attributen ärger bereiten...

Meiner meinung nach sollte man auch getrennt nach verzeichnissen und datei suchen
Doppelt suchen bedeutet auch doppelten Plattenzugriff und der ist bekanntlich seeeehr langsam.
Würde vorschlagen stattdessen mit zwei Strings zu arbeiten - einen für die gefundenen Ordner + einen für die Dateien und diese am Ende des Suchdurchlaufs zusammenfügen und als als von der Funktion zurückgeben lassen. Dann hat die Einträge am Ende wie gewünscht getrennt.
Ein einfaches Sortieren (Sorted:=true) der List am Ende finde ich schaft IHMO auch eine gute übersicht.

CU Borlander

bei Antwort benachrichtigen
mr.escape Borlander „Da hat sich der Fehlerteufel aber wieder böse bei mir zugeschlagen... Macht...“
Optionen
Da hat sich der Fehlerteufel aber wieder böse bei mir zugeschlagen...
Na und? Passiert doch jedem mal. Und solange nix kaputt geht...

0
Dass könnte allerdings bei der Überprüfung von mehreren Attributen ärger bereiten...
könnte schon, bei mehreren attributen wird man aber sowieso angeben müssen, welche vorhanden sein müssen, welche nicht vorhanden sein dürfen und welche egal sind. Hier ging es nur um verzeichnisse.

Doppelt suchen bedeutet auch doppelten Plattenzugriff und der ist bekanntlich seeeehr langsam.
Nicht wirklich, denn die suche findet zweimal direkt nacheinander innerhalb des selben verzeichnisses statt und wird sicher aus dem cache bedient (sind ja nur die einträge und nicht die daten, d.h. durchschnittlich einige zig bytes, die ja wohl locker im cache verwaltet werden können, vor allem weil sie ja eben gerade verwendet wurden). Die funktion bleibt ja fast gleich, rekursiv, etc. aber zuerst werden die ordner gesucht und anschliessen die nicht ordner. Wenn man das zeug danach sortiert, ist es aber egal.

mr.escape
"The man who trades freedom for security does not deserve nor will he ever receive either." - Benjamin Franklin"Wer seine Freiheit aufgibt, um Sicherheit zu erreichen, wird beides verlieren." - Georg Christoph Lichtenberg
bei Antwort benachrichtigen
The_Wise Nachtrag zu: „Delphi 5 - Prozedur für Dateisuche“
Optionen

Habe die ganze Prozedur umgeschrieben:

procedure TMainForm.SearchFile (Pfad: String);
var rec: TSearchRec;
begin
FindFirst(Pfad+'*.*', faAnyFile, rec);
FindNext(rec);
while FindNext(rec) = 0 do
begin
if rec.Attr = faDirectory then
SearchFile(pfad+rec.Name+#92) //92=' \\ '
else
if RightFile(rec.name) = true then
ListBox1.Items.Add(Pfad + '\\' + rec.Name);

Application.ProcessMessages;
end;

FindClose(rec);
end;

Nun funkt es.
Dennoch danke für die Hilfe !

bei Antwort benachrichtigen
Andreas42 The_Wise „Habe die ganze Prozedur umgeschrieben: procedure TMainForm.SearchFile Pfad:...“
Optionen

Hi!

Falls sich das bei Delphi nicht geändert (was ich vermute), dann findet FindFirst() bereits den ersten Eintrag. Danach liest du mit FindNext() bereits den zweiten.
Die Abfrage in der While-Anweisung liest dann bereits den dritten Eintrag und dieser wird dann als erster bearbeitet. Du iognorierst also die ersten beiden Einträge.

Soweit ich das Blicke sind die ersten beiden gefundenen Einträge immer die Pseudoverzeichnisse "." und "..". Die gibt es allerdings nur in Unterverzeichnissen. damit stimmt deine Abfrage für Rekursivaufrufe. Im Rootverzeichnis einer Platte dürften dann aber die ersten beiden Einträge des Verzeichnisses ignoriert werden (falls die Suche in einem Rootverzeichnis los geht).

Versteckte Verzeichnisse werden übrigends auch ignoriert (auch solche mit gesetzten Schreibschutz oder System-Attribut, aber das kann ja gewünscht sein). Auf meinem Win98-System tummeln sich massenweise Verzeichnisse mit solchen Attributen...

Bis denn
Andreas

Hier steht was ueber mein altes Hard- und Softwaregedoens.
bei Antwort benachrichtigen