![]() |
FindFirst, FindNext
Delphi-Quellcode:
gibt auch 'blabla' zurück, obwohl in blabla kein Punlt drin ist. Warum???
FindFirst('*.*', faanyfile, dat);
FindNext('*.*', faanyfile, dat); FindNext('*.*', faanyfile, dat); und wie kann man nur nach Dateien suchen (Ordner ausschließen)? --- Nochwas:
Delphi-Quellcode:
liefert '..' zurück. Das gibt es doch aber gar nicht?!?!
SetCurrentDir('c\:')
FindFirst('*.*', c, dat); FindNext(dat); |
Re: FindFirst, FindNext
Zitat:
Grüsse, Daniel :hi: |
Moin Nailor,
die Suchmaske *.* bedeutet: Suche nach allen Dateinamen (erster *) und allen Endungen (.*) Anders formuliert: Suche nach allem. Logisch, dass dann auch alles zurückgeliefert wird. Die Suche nur nach Dateien sollte so gehen
Delphi-Quellcode:
Schau Dir dazu mal am besten die möglichen Werte für faXXXX in der Hilfe an. Wichtig: Bei solchen Werten (Flags) immer mit or zusammenfügen und mit and not löschen niemals mit +/-. Das würde zwar meist gutgehen, muss es aber nicht, da diese Konstanten Bitmuster enthalten und somit auch, wenn man es nicht erwartet, einen negativen Wert enthalten können, so dass aus der Subtraktion unerwartet eine Addtion wird. Kann interessante Probleme zur Folge haben.
FindFirst('*.*',faAnyFile and not faDirectory,dat)
Ich für meinen Teil suche immer erst mal nach allem (faAnyFile) und filtere dann hinterher (z.B. if (dat.Attr and faDirectory) = 0 then, wenn ich Directories herausfiltern will), da ich den FindFirst Filtern bei der Abfrage nicht so recht traue ;-) Ist aber bestimmt Geschmackssache. Den Eintrag .. gibt es durch aus. Ebenso auch den Eintrag . Nach diesem beiden wird man immer Filtern müssen, denn sie werden wohl auch immer auftauchen (zumindest bei *.*) Mit .. kann man zum übergeordneten Verzeichnis verzweigen, mit . ist das aktuelle Verzeichnis gemeint. Mach am besten mal eine Konsole auf und lass Dir mal mit DIR den Verzeichnis inhalt anzeigen. Dabei werden . und .. auch angezeigt (als erstes) Ein leeres Verzeichnis enthält dann auch nur diese beiden. Wenn Du in einem Unterverzeichnis mal Dir .. eingibst erhältst Du den Inhalt des übergeorneten Verzeichnisses, mit Dir . das gleiche wie mit Dir und Dir *.*. Die Abfrage müsste also lauten:
Delphi-Quellcode:
Ach ja:
if (dat.name <> '.') and (dat.name <> '..') then
begin // Mach was mit dem gefundenen Namen end; Nicht mit dat.name[1] <> '.' abfragen. Punkte sind in Datei und Verzeichnisnamen zugelassen, auch als erstes Zeichen, und somit können einem Dateien/Verzeichnisse entgehen. Nachtrag: Du kannst bei FindFirst auch einen kompletten Startpfad für die Suche angeben, und brauchst diesen nicht mit SetCurrentDirectory zu setzen. |
Ergänzung zu FindFirst
Hallo Nailor,
'C\:' kann jeden in den Wahnsinn treiben!! :twisted: Der Vollständigkeit halber sollte am Ende noch "FindClose" stehen.
Delphi-Quellcode:
procedure TForm1.MyNameClick(Sender: TObject);
var srec : TSearchRec; begin .... if FindFirst('C:\Pfad\*.*', faAnyFile, srec) = 0 then begin repeat .... // jedemenge Befehle .... until FindNext(srec) <> 0; end; FindClose(srec); .... end; mfg eddy |
Moin eddy,
wenn Du es ganz vollständig haben willst
Delphi-Quellcode:
try/finally (Resourcenschutzblock) um sicherzustellen, dass die durch den erfolgreichen Aufrufe von FindFirst belegten Resourcen auch wieder freigegeben werden.
procedure TForm1.MyNameClick(Sender: TObject);
var srec : TSearchRec; begin .... if FindFirst('C:\Pfad\*.*', faAnyFile, srec) = 0 then begin try repeat .... // jedemenge Befehle .... until FindNext(srec) <> 0; finally FindClose(srec); end; end; .... end; Das FindClose hab' ich etwas nach oben gerückt, da es ja nur bei erfolgreichem Aufruf von FindFirst notwendig ist. |
Thx, waren ein paar gute Tipps dabei, und sorry für die Mühe mit dem Typo bei C-Doppelpunkt-Backslash bzw. C-Backslash-Doppelpunkt. Hab mich echt vertan :oops:
Aber trotzdem:
Delphi-Quellcode:
Lifert im Gegensatz zu jedem andern Verzweichnis nicht '.' zurück. Obwohl doch auch im Hauptverzeichnis das aktuelle Verzeichnis mit '.' bezeichnet sein müsste...
procedure TForm1.Button1Click(Sender: TObject);
var dat: tsearchrec; begin SetCurrentDir('c:\'); FindFirst('*.*', faanyfile, dat); Caption := dat.name; end; |
Moin Nailor,
stimmt, und auch kein .. ;-) Ich werde mir das nochmal auf einem 9x und, nach Möglichkeit NT 4 Rechner ansehen, da ich mir sicher bin, dass ich diese beiden Angaben auch schon im Root gesehen habe. BTW: Du hast das FindClose vergessen ;-) |
Ein '..' wäre ja auch falsch weils das nicht gibt. Aber ein '.' gibt es ja. Aber Delphi will es nicht finden.
FineClose lohnt sich bei so Hammer-Testprogrammen mit nur einem Button und 3 Zeilen Code, die noch nichteinmal gespeichrt werden nicht :wink: Delphi gibt doch die verwendeten Resourcen beim Beenden eh frei, oder nicht? |
Moin Nailor,
sicher, dass ist bei einem solchen Test nicht zwingend notwendig, aber ich finde je mehr es einem "in Fleisch und Blut" übergeht so etwas mit zu schreiben, umso geringer ist die Gefahr es zu vergessen wenn es notwendig ist. ;-) Gerade, dass ich in einem Root Verzeichnis mal ein .. gesehen habe hatte mich so verblüfft, da es das, wie Du ja schon so richtig sagst, eigentlich nicht geben kann. |
Was mach ich jetzt schon wieder falsch?
Delphi-Quellcode:
Das Obere zeigt alle Ordner und alle Dateien an...
procedure TForm1.FormCreate(Sender: TObject);
var a: TSearchRec; begin ListBox1.Clear; SetCurrentDir('C:\'); FindFirst('*.*', faDirectory , a); ListBox1.Items.Append(a.Name); while FindNext(a) = 0 do ListBox1.Items.Append(a.name); FindClose(a); ListBox1.Items.Append(''); ListBox1.Items.Append(stringofchar('#', 75)); ListBox1.Items.Append(''); if FindFirst('*.*', faAnyFile and not faDirectory, a) = 0 then begin ListBox1.Items.Append(a.Name); while FindNext(a) = 0 do ListBox1.Items.Append(a.name); end else ListBox1.Items.Append('no files found'); FindClose(a); end; PS: Die Delphi-Hilfe:
Delphi-Quellcode:
arbeitet auch ohne and/and not. Nur zum Testen von gesetzten Werten:
procedure TForm1.Button1Click(Sender: TObject);
var sr: TSearchRec; FileAttrs: Integer; begin StringGrid1.RowCount := 1; if CheckBox1.Checked then FileAttrs := faReadOnly else FileAttrs := 0; if CheckBox2.Checked then FileAttrs := FileAttrs + faHidden; if CheckBox3.Checked then FileAttrs := FileAttrs + faSysFile; if CheckBox4.Checked then FileAttrs := FileAttrs + faVolumeID; if CheckBox5.Checked then FileAttrs := FileAttrs + faDirectory; if CheckBox6.Checked then FileAttrs := FileAttrs + faArchive; if CheckBox7.Checked then FileAttrs := FileAttrs + faAnyFile; with StringGrid1 do begin RowCount := 0; if FindFirst(Edit1.Text, FileAttrs, sr) = 0 then begin repeat if (sr.Attr and FileAttrs) = sr.Attr then begin RowCount := RowCount + 1; Cells[1,RowCount-1] := sr.Name; Cells[2,RowCount-1] := IntToStr(sr.Size); end; until FindNext(sr) <> 0; FindClose(sr); end; end; end; To test for an attribute, combine the value of the Attr field with the attribute constant with the and operator. If the file has that attribute, the result will be greater than 0. For example, if the found file is a hidden file, the following expression will evaluate to True: (SearchRec.Attr and faHidden) <> 0. |
Moin Nailor,
Zitat:
Mit anderen Worten: FindFirst sucht immer nach allen Dateien (was sich auch mit den zugrunde liegenden API Funktionen deckt), und zeigt die im Filter angegebenen zusätzlich an. Der Filter gibt also nicht an, was man nur haben will, sondern was man auch haben will. Also, wie schon weiter oben gesagt: Nimm' faAnyFile und filtere hinterher das raus, was Du haben willst. Geht nicht anders. |
also
To test for an attribute, combine the value of the Attr field with the attribute constant with the and operator. If the file has that attribute, the result will be greater than 0. For example, if the found file is a hidden file, the following expression will evaluate to True: (SearchRec.Attr and faHidden) <> 0. Demnach nach faanyfile suchen, für Ordner (SearchRec.Attr and fadirectory) <> 0 nehmen und für dateien: FindFirst('*.*', 0, SearchRec) oder wie :?: :?: :?: |
Moin Nailor,
immer nach faAnyFile suchen. Bei Directories dann
Delphi-Quellcode:
und bei Dateien
if (srSearch.Attr and faDirectory) <> 0 then // Verzeichnis
// oder if (srSearch.Attr and faDirectory) = faDirectory then // Verzeichnis
Delphi-Quellcode:
Mit der Methode bin ich bislang gut gefahren.
if (srSearch.Attr and faDirectory) = 0 then // Kein Verzeichnis
// oder if (srSearch.Attr and faDirectory) <> faDirectory then // Kein Verzeichnis Eine kleine Frage noch: Warum benutzt Du eigentlich immer die Kombination aus SetCurrentDir und FindFirst mit Dateimaske? Als ersten Parameter akzeptiert FindFirst auch einen kompletten Pfad. Ich frage nur, weil ich das bisher noch nie so gesehen habe. Eines noch zum +/or "Problem": Ich sage nicht, dass es grundsätzlich nicht geht Flags mit + zu verknüpfen, nur kann immer der Fall eintreten, das die Verwendung von arithmetischen Operatoren zu Fehlern führen kann. Da sich dies, ohne die genauen numerischen Werte zu kennen, aber nicht vorhersagen lässt, finde ich es einfach sinnvoller Flags nur mit logischen Operatoren zu bearbeiten. Dann braucht man sich nicht darum zu kümmern, ob das in dem speziellen Falle anders geht oder nicht. Intern benutzt Borland übrigens auch or um die Flags zu Verknüpfen. |
1. Weil ich mir noch keine Gedenken darüber gemacht habe, dass es natürlich auch reicht, den Pfad so weit wie nötig anzugeben und weil in der Hilfe halt steht, dass das aktuelle Verzeichnis durchsucht wird, daher SetCurrentDir. Ist aber doof. Hast Recht, weil das dann ja verstellt bleibt.
2. Flags mit arith. Ich bin halt nie auf die Idee gekommen, dass das Fehler geben könnte. genau wie bei if boolean = true then |
Noch eine Frage: Wie krieg ich den kompletten Pfad (mit oder ohne Dateiname angehängt)?
|
Moin Nailor,
den kompletten Pfad von was? |
Von hier nach München :wink:
Von einer Datei natürlich... |
Moin Nailor,
das war soweit schon klar, nur:
Das nur mal so, was mir auf anhieb einfällt. ;-) |
Das wenn man mit FindFirst sucht,
man aus dem TSearchRec.Name den kompletten Pfad der Datei, die gefunden wurde bekommt. |
Moin Nailor,
ach so ;-) ( das ;-) war bloss für mich in Erinnerung an meine eigenen Anfänge mit FindFirst, das Problem hatte ich nämlich auch) Gar nicht, den Pfad musst Du wissen, was ja auch keine Schwierigkeit sein dürfte, denn den gibst Du ja auf die eine oder andere Weise auch an, bevor Du FindFirst aufrufst. SearchRec.Name gibt Dir nur den Namen eines im angegebenen Pfad gefundenen Elementes zurück (könnte ja auch ein Directory sein). |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:19 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