Alle anderen Antworten konzentrieren sich darauf, jede Datei einzeln zu überprüfen, aber wenn sich die Dateien alle in einem Verzeichnis (Ordner) befinden, könnte es viel effizienter sein, nur das Verzeichnis lesen und prüfen Sie, ob alle gewünschten Dateinamen vorhanden sind.
Dies kann sogar effizienter sein, wenn die Dateien über mehrere Verzeichnisse verteilt sind, je nach dem genauen Verhältnis von Verzeichnissen zu Dateien. Sobald sich jede Zieldatei in einem eigenen Verzeichnis befindet oder sich viele andere Dateien in denselben Verzeichnissen befinden, die nicht überprüft werden sollen, würde ich erwarten, dass es letztendlich weniger effizient ist als jede Datei einzeln zu überprüfen.
Eine gute Heuristik: Es ist viel schneller, mit einer Menge von Daten zu arbeiten, die man bereits hat, als das Betriebssystem nach einer beliebigen Menge von Daten zu fragen. Der Overhead bei Systemaufrufen ist im Vergleich zu einzelnen Maschinenbefehlen enorm. Es ist also fast immer schneller, das Betriebssystem zu fragen: "Gib mir die gesamte Liste der Dateien in diesem Verzeichnis" und sich dann durch diese Liste zu wühlen, und langsamer, das Betriebssystem zu fragen: "Gib mir Informationen über diese Datei", "Okay, jetzt gib mir Informationen über diese andere Datei", "Jetzt gib mir Informationen über ...", und so weiter.
Jede gute C-Bibliothek implementiert ihre "Iteration über alle Dateien in einem Verzeichnis"-APIs auf effiziente Weise, genau wie gepufferte E/A - intern liest sie eine große Liste von Verzeichniseinträgen vom Betriebssystem auf einmal, auch wenn die APIs so aussehen, als würde man das Betriebssystem nach jedem Eintrag einzeln fragen.
Wenn ich also diese Anforderung hätte, würde ich
- alles zu tun, um die Gestaltung und Nutzung so zu fördern, dass sich alle Dateien in einem Ordner befinden und keine anderen Dateien in diesem Ordner sind,
- die Liste der Dateinamen, die ich benötige, in einer Datenstruktur im Speicher ablegen, die O(1) oder zumindest O(log(n)) Such- und Löschzeiten hat (wie eine Hash-Map oder ein Binärbaum),
- die Dateien in diesem Verzeichnis auflisten und nach und nach aus der "Liste" (Hash-Map oder Binärbaum) im Speicher "abhaken" (löschen).
Außer je nach dem genauen Anwendungsfall würde ich vielleicht statt des Löschens von Einträgen aus einer Hash-Map oder einem Baum ein "Habe ich diese Datei?"-Boolesches Ergebnis für jeden Eintrag verfolgen und eine Datenstruktur finden, die die Frage "Habe ich jede Datei?" O(1) macht. Vielleicht ein Binärbaum, aber die Struktur für jeden Nicht-Blattknoten hat auch einen Booleschen Wert, der ein logisches Und der Booleschen Werte seiner Blattknoten ist. Das skaliert gut - nachdem man einen Booleschen Wert in einem Blattknoten gesetzt hat, geht man einfach den Baum hinauf und setzt den Booleschen Wert jedes Knotens "habe ich das?" mit der &&
des booleschen Wertes des untergeordneten Knotens (und Sie brauchen nicht auf die anderen untergeordneten Knoten zu rekursieren, denn wenn Sie diesen Prozess jedes Mal konsequent durchführen, wenn Sie eines der Blätter auf true setzen, werden sie nur dann auf true gesetzt, wenn alle ihre untergeordneten Knoten true sind).
Leider gibt es keine Standard bis C++17 zu tun.
C++17 hat std::filesystem::directory_iterator
.
Natürlich gibt es eine entsprechende boost::filesystem::directory_iterator
was vermutlich auch in älteren Versionen von C++ funktioniert.
Das, was einem Standard-C-Weg am nächsten kommt, ist opendir
y readdir
von dirent.h
. Das ist eine Standard-C-Schnittstelle, sie ist nur in POSIX standardisiert und nicht im C-Standard selbst. Sie ist auf Mac OS, Linux, allen BSDs, anderen UNIX/UNIX-ähnlichen Systemen und jedem anderen POSIX/SUS-System sofort verfügbar. Für Windows gibt es eine dirent.h
Umsetzung die Sie einfach herunterladen und in Ihrem Include-Pfad ablegen müssen.
Da Sie jedoch nach dem schnellste Vielleicht sollten Sie sich nicht nur mit den tragbaren/standardmäßigen Produkten befassen.
Unter Linux können Sie die Leistung möglicherweise optimieren, indem Sie die Puffergröße manuell mit dem Raw-Systemaufruf angeben getdents64
.
Unter Windows, nach ein wenig Suchen, es sieht so aus Für eine maximale Leistung sollten Sie Folgendes verwenden FindFirstFileEx
con FindExInfoBasic
y FIND_FIRST_EX_LARGE_FETCH
wenn Sie können, was viele der Open-Source-Bibliotheken wie die oben genannte dirent.h
für Windows scheinen nicht zu funktionieren. Aber für Code, der mit Dingen arbeiten muss, die älter sind als die letzten paar Windows-Versionen, können Sie genauso gut einfach die unkomplizierte FindFirstFile
ohne die zusätzlichen Flaggen.
Der Plan 9 wird von keinem der oben genannten Pläne abgedeckt, und Sie benötigen dort dirread
o dirreadall
(letzteres, wenn Sie sicher davon ausgehen können, dass Sie genügend Speicher für den gesamten Verzeichnisinhalt haben). Wenn Sie aus Leistungsgründen mehr Kontrolle über die Puffergröße haben wollen, verwenden Sie einfach read
o read
und dekodieren die Daten des Verzeichniseintrags - sie liegen in einem dokumentierten, maschinenunabhängigen Format vor, und ich glaube, es werden Hilfsfunktionen angeboten.
Ich weiß nichts über andere Betriebssysteme.
Vielleicht bearbeite ich diese Antwort später mit einigen Tests. Andere können auch gerne Testergebnisse einfügen.