Dateien in einem Verzeichnis auflisten (FindFirstFile/FindNextFile)
-
Ich habe den oben genannten Beitrag in den FAQ gelesen und so implementiert.
Dabei fiel mir während des Debuggens auf, das bei mir zumindest der erste Aufruf von FindFirstFile nicht den "." ergibt, sondern bei mir wenn ich den Ordner C:\ durchsuche der erste Aufruf den Ordner I386 ergibt. Wenn ich das Programm dann bis zum Ende weiterlaufen lasse wird der genannte Ordner auch nicht mehr gefunden.
Ich möchte mir zwar nicht anmaßen zu behaupten in dem Beitrag wäre ein Fehler, jedoch macht es auf mich diesen Eindruck,falls dies der Fall wäre sollte man das auf jedenfall korrigieren. Ich habe mich jedenfalls nicht getraut in den Beitrag direkt zu posten (die FAQ ist für mich heilig).
Kann irgendjemand anders diese Beobachtung bestätigen?Ich habe den Code jetzt so modifiziert:
HANDLE fHandle; WIN32_FIND_DATA wfd; // Erste Datei im Verzeichnis "c:\windows\desktop\" holen: fHandle=FindFirstFile("c:\\windows\\desktop\\*",&wfd); //Wenn das Ergebnis einen Punkt liefert ignoriere diesen und mach weiter if (wfd.cFileName[0]=='.'); else if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // Datei ist keine, sondern ein Verzeichnis... // Hier könnte man dasselbe nochmal machen, um auch die // Unterverzeichnisse zu scannen ;-) } else { MessageBox(0,wfd.cFileName,"Folgende Datei gefunden:",0); } while (FindNextFile(fHandle,&wfd)) { //Wenn das Ergebnis einen Punkt liefert ignoriere diesen und mach weiter if (wfd.cFileName[0]=='.'); else if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { // Datei ist keine, sondern ein Verzeichnis... // Hier könnte man dasselbe nochmal machen, um auch die // Unterverzeichnisse zu scannen ;-) } else { MessageBox(0,wfd.cFileName,"Folgende Datei gefunden:",0); } } FindClose(fHandle);
-
Ich habe es jetzt nochmal modifiziert und die Rekursion eingearbeitet.
Dabei habe ich zwei globale Variablen mitzählen lassen, eine für die Ordner und eine für die Dateien und dieses Ergebnis mit dem vom Windows Explorer verglichen.
Ich habe jeweils über eine komplette Partition testen lassen.
Ergebnis:
C: WindowsExplorer 91496 Dateien, 5616 Ordner
mein Prog 91493 Dateien, 5616 OrdnerWindowsExplorer 32611 Dateien, 2417 Ordner
mein Prog 32611 Dateien, 2417 OrdnerEs fällt auf, das mein Programm auf Laufwerk C: 3 Dateien weniger findet, meine erste Vermutung war der Papierkorb also Papierkorb lehren. Jedoch Fehlanzeige, der Inhalt des Papierkorbes wird bei beiden mitgezählt. Ich glaube bei mir gibt es einfach drei Dateien, die nur Windows findet. Das Ergebnis von
stimmt ja auch.
Ich glaube damit kann ich leben.Falls jemand das auch nachprüfen möchte, sollte er im Windows Explorer unter
Extras Ordneroptionen Ansichten den Haken bei "Geschützte Systemdateien ausblenden" entfernen.Gruß Alex
PS: Über Anmerkungen würde ich mich sehr freuen!
Nochwas: Ich dachte zuerst ich könnte einen PerformanceVergleich machen zwischen meinem Programm und dem Windows Explorer, das sollte jedoch nicht direkt nacheinander gemacht werden da das Dateisystem irgendwo im Speicher abgelegt wird und der zweite Aufruf egeal ob von meinem Progamm oder Windows Explorer deutlich schneller abläuft als der erste.
-
Der Code ignoriert Dateinamen, die mit einem Punkt anfangen, vermutlich, um "." und ".." zu überspringen. Allerdings können Dateinamen durchaus mit einem Punkt anfangen. Man kann solche Dateien und Ordner nur nicht mit dem Explorer erzeugen. Vielleicht hast du auf C: ein paar von diesen Dateien.
-
Danke MFK,
Du hast vollkommen recht, ich habe mein Laufwerk durchsucht und da fand ich genau 3 Dateien. Also die if Bedingung geändert und jetzt klappts, Ergebnisse stimmen überein. Aber du mußst zugeben war doch eine megastarke Fehleranalyse von mir, "ich weiß es nicht -> Windows ist daran schuld".
Für den den es intereessiert die geänderte if Bedingung:
if ( (wfd.cFileName[0]=='.') && ( (wfd.cFileName[1]=='.'&& wfd.cFileName[2]==0) || wfd.cFileName[1]==0) );
Diese muß zweimal eingefügt werden.
Über weiter Kommentare und Veresserungsvorschläge freue ich mich.Gruß Alex
-
Alex_H schrieb:
if ( (wfd.cFileName[0]=='.') && ( (wfd.cFileName[1]=='.'&& wfd.cFileName[2]==0) || wfd.cFileName[1]==0) )
Nur damit es vielleicht etwas übersichtlicher und leichter zu lesen ist:
if( (lstrcmp(wfd.cFileName,".")==0) || (lstrcmp(wfd.cFileName,"..")==0) )
-
Danke sieht wirklich übersichtlicher aus, wobei man statt dem Vergleich mit NULL auch den Wert invertieren kann.
Jedoch eine Frage, lstrcmp() bedeutet jedesmal einen Funktionsaufruf (Daten auf den Stack, Daten wieder runter vom Stack), und das 2mal (2x lstrcmp) ist das wirklich sinnvoll, bei einer Funktion die so wie in meinem Fall beim Laufwerk C: über 100.000 mal aufgerufen wird, ich nehme an das die Funktion lstrcmp() zu groß ist als das der Compiler sie inline kreiert?Aber nochmal zum Thema kann jemand die Feststellung von mir bestätigen. Oder ist mein System nur eine "Ausnahme"?
Gruß Alex
-
Alex_H schrieb:
wobei man statt dem Vergleich mit NULL auch den Wert invertieren kann.
So wurde die Funktion halt in der MSDN aufgerufen... Bin mir auch nicht sicher, ob ein !lstrcmp(...) schneller ist, da da dann ja wohl erst der Wert erst in einen bool umgewandelt werden muss, oder?!
Alex_H schrieb:
Jedoch eine Frage, lstrcmp() bedeutet jedesmal einen Funktionsaufruf (Daten auf den Stack, Daten wieder runter vom Stack), und das 2mal (2x lstrcmp) ist das wirklich sinnvoll, bei einer Funktion die so wie in meinem Fall beim Laufwerk C: über 100.000 mal aufgerufen wird, ich nehme an das die Funktion lstrcmp() zu groß ist als das der Compiler sie inline kreiert?
Das stimmt allerdings auch wieder - käme also auf einen Test an
-
Danke Flenders für die Arbeit die du mir gibst:
Also wie teste ich sowas?
Ich dachte zuerst ich mache jeweils ein Programm lege es auf den Desktop und starte vor jedem Test den Rechner neu. Ich glaube dann bin ich den ganzen Tag beschäftigt.
Da uns ja nicht die Geschwindigkeit der Festplatte interesiert sondern der Funktion, kann er die Daten ruhig aus dem Cache oder Ram lesen (welches genau weiß ich nicht). Ich habe alle unnötigen Dienste deaktiviert und den Rechner vom Internet getrennt. Zudem habe ich den Rechner in der Energieverwaltung auf Desktop gestellt(ja ich arbeite am Notebook AMD Sempron 3000+).
Ich hab mich also in die Funktionen
QueryPerformanceFrequency();
QueryPerformanceCounter();
eingelesen und werte die rufende Funktion aus.Ich habe beide Programme gestartet. und abwechselnd deins und meins 3 Partitionen durchsuchen lassen (141189 Dateien, 10003 Ordner), solange bis ich konstante Werte hatte.
Dann habe ich 10 mal abwechselnd 10mal deins , 10 mal meins, durchsuchen lassen und die Werte mitgeschrieben. Insgesamt 200 FunktionsaufrufeDeine Lösung ergibt Ergebnisse von 1716 bis 1763 ms-> Durchschnitt 1740 ms
Meine Lösung ergibt Ergebnisse von 1584 bis 1628 ms-> Durchschnitt 1624 msergibt eine Differenz von 116 ms. Was hälst Du von dem Ergebnis?
Ach ja ich programmiere mit dem Borland Builder.
So viel Arbeit und ich wollte den Rechner nur nach doppelte Dateien dursuchen lassen.
Ich weiß aber immer noch nicht ob jemand den Fehler den ich in der FAQ vermute bestätigen kann.
Gruß Alex
-
Alex_H schrieb:
Danke Flenders für die Arbeit die du mir gibst:
Kein Problem, das mache ich doch gern
Alex_H schrieb:
Deine Lösung ergibt Ergebnisse von 1716 bis 1763 ms-> Durchschnitt 1740 ms
Deine Lösung ergibt Ergebnisse von 1584 bis 1628 ms-> Durchschnitt 1624 msergibt eine Differenz von 116 ms. Was hälst Du von dem Ergebnis?
Meintest du beim zweiten nicht "Meine Lösung" - also die von dir?!
Ist zwar schon ein wenig, aber nicht die Welt - so ist das eben mit Code-Optimierungen meistens. Höhere Lesbarkeit führt oft zu höherem Zeitbedarf bzw. Zeitersparnis geht oft mit immer stärker unleserlichem Code einher. Leider.Alex_H schrieb:
Ich weiß aber immer noch nicht ob jemand den Fehler den ich in der FAQ vermute bestätigen kann.
Bei mir kommen komischerweise weder . noch .. im Ergebnis vor - sprich auch die ersten 2 Treffer, die rausgefiltert werden enthalten eigentlich schon sinnvolle Daten.
-
Den Quellcode in der FAQ hatte ich ja verbrochen, kann gut sein dass ich das "." und ".." mit php verwechselt hab oder so
-
Danke flenders,
habs sofort editiert (sch... copy paste).
Mir ist es nur aufgefallen, weilich zuerst versucht habe es selbst zu implementieren und keine Ahnung von dem . bzw .. hatte Folge mein Programm hat sich ins unendliche rekursiv aufgerufen (wieso ist mein Stack nicht übergelaufen). Und beim Debuggen fiehl mir dann auf das er im Laufwerk c: zuerst o.g. Ordner gefunden hat, als er dann reinging kam dann der . und danach .. Ich habe es jetzt nochmal versucht und mir ist aufgefallen das er mit FindFirstFile einen Ordner zurückgibt wenn ich direkt im Laufwerk suche also C: ;; oder E: wenn ich mit der Suche in einem Unterverzeichnis beginne kommt so wie Geeky das in den FAQ geschrieben hat . und dann .. naja wie auch immer.
An Geeky:
Du solltest nicht zu hart mit Dir ins Gericht gehen.
Wie es mir gerade scheint ist das von System zu System unterschiedlich. Siehe Flenders und mich.Gruß
AlexPS: Wieso werden meine Texte immer so lang, erzähl ich zuviel?
-
Ich hatte es aber auch nur mit C:\* versucht - bei einem Unterverzeichniss kommt tatsächlich auch noch . und .. (wobei letzteres bei einem Root-Verzeichnis auch keinen Sinn macht)
-
Hmm, dann müsste man das in der FAQ besser mal ergänzen
-
Mein Vorschlag:
HANDLE fHandle; WIN32_FIND_DATA wfd; fHandle=FindFirstFile("C:\\*",&wfd); do { // Eintrag nur behandeln, wenn es nicht . oder .. ist (werden nur bei Unterverzeichnissen mit zurückgeliefert) if (!( (wfd.cFileName[0]=='.') && ( (wfd.cFileName[1]=='.' && wfd.cFileName[2]==0) || wfd.cFileName[1]==0 ) )) { if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { MessageBox(0,wfd.cFileName,"Folgendes Verzeichnis wurde gefunden:",0); // Datei ist keine, sondern ein Verzeichnis... // Hier könnte man dasselbe nochmal machen, um auch die // Unterverzeichnisse zu scannen ;-) } else { MessageBox(0,wfd.cFileName,"Folgende Datei gefunden:",0); } } } while (FindNextFile(fHandle,&wfd)); FindClose(fHandle);
-
geeky schrieb:
Hmm, dann müsste man das in der FAQ besser mal ergänzen
Deswegen habe ich dieses Thema nochmal zur Diskussion gebracht.
zu flenders:
Bedeutend schöner als mein Vorschlag, die Modifikation auf Do while ist super.
Eine Variante wäre natürlich auch das lstrcmp(), aber das müßten einige villeicht erst noch nachlesen (mußte ich auch).Ich unterstütze Deinen Vorschlag
Gruß
Alex