it-swarm.com.de

Wie kann ich Dateien in einem Verzeichnis mit der Windows-API auflisten?

Ich habe diesen Code und zeigt den Ordner mit dem Verzeichnis selbst und nicht dessen Inhalt an. Ich möchte den Inhalt anzeigen. Ich möchte nicht boost :: filesystem verwenden. 

Wie kann ich das beheben?

Code:

#include <windows.h>
#include <iostream>

int main()
{
    WIN32_FIND_DATA data;
    HANDLE hFind = FindFirstFile("C:\\semester2", &data);      // DIRECTORY

    if ( hFind != INVALID_HANDLE_VALUE ) {
        do {
            std::cout << data.cFileName << std::endl;
        } while (FindNextFile(hFind, &data));
        FindClose(hFind);
    }
}

Ausgabe:

semester2
8
John Escobia
HANDLE hFind = FindFirstFile("C:\\semester2", &data);       // DIRECTORY

Sie haben das Verzeichnis, weil Sie danach gefragt haben. Wenn Sie die Dateien wünschen, fragen Sie nach:

HANDLE hFind = FindFirstFile("C:\\semester2\\*", &data);  // FILES

(Sie können stattdessen *.* verwenden, wenn Sie dies vorziehen, aber anscheinend funktioniert dies nur wegen eines Rückwärtskompatibilitäts-Hacks. Daher sollte es wahrscheinlich vermieden werden. Siehe Kommentare und Antwort von RbMm.)

12
Harry Johnston

Lassen Sie mich einige Anmerkungen zu "*.*" vs "*" machen. Diese Ordner sind nicht gleich.

In unserem Ordner können zwei verschiedene Dateien vorhanden sein: somefile und somefile..

Wenn wir die Low-Level-API ZwQueryDirectoryFile mit "*.*" als Suchausdruck verwenden (dies ist der 10. Parameter - FileName [in, optional]) -, erhalten wir nur somefile.. Wenn wir jedoch "*" verwenden, würden wir beide Dateien erhalten - somefile und somefile. 

Wenn wir FindFirstFile("C:\\semester2\\*.*", &data); versuchen, können wir feststellen, dass beide Dateien somefile und somefile. zurückgegeben werden. Hier haben also "*.*" vs "*" die gleiche Wirkung - kein Unterschied in der Verwendung.

Warum passiert das? In FindFirstFileEx in kernelbase (kernel32) sollten Sie die "*.*"-Maske besonders prüfen. Wenn sie wahr ist, ersetzen Sie "" (Ein leerer Name, der dieselbe Wirkung wie "*" hat). 

Ich denke, dies geschieht, um einen sehr häufigen Fehler zu beheben, wenn Benutzer "*.*" anstelle des korrekten "*" übergeben, und für die Abwärtskompatibilität mit älterem Code.

. und .. sind nicht wirklich Teil des Verzeichnisses, da es unter .__ gespeichert ist. Festplatte, aber von der Win32-API hinzugefügt.

Das ist nicht wahr. 

  • für das FAT-artige Dateisystem wird dies wirklich als erster Eintrag im FAT-Verzeichnis gespeichert. 
  • in NTFS gibt es keine solchen Einträge, aber NTFS.sys fügt diese beiden Einträge künstlich hinzu, wenn sie in mask sind. 

Dies geschieht also nicht auf Win32-API-Ebene, sondern im Kernel - auf Treiberebene.

Zusammenfassend wird "*.*" mit der Win32-API jetzt korrekt funktionieren, aber jetzt ist die korrekte und saubere Methode die Verwendung von "*".
"*.*" wird mit ZwQueryDirectoryFile api falsch sein.

6
RbMm

Die Antwort von Harrys liefert tatsächlich Dateien und Ordner mit einer Erweiterung in Ihrem gewünschten Ordner "C:\\semester2".

Wenn Sie beispielsweise einen Ordner mit dem Namen "C:\\semester2\\math.course" haben, wird er auch vom obigen Beispiel gefunden. Wenn Sie eine Datei mit dem Namen "C:\\semester2\\math_scores" haben (beachten Sie, dass sie keine Erweiterung hat), wird sie nicht gefunden.

Unter Berücksichtigung des Vorstehenden würde ich folgende Lösung vorschlagen:

HANDLE hFind = FindFirstFile("C:\\semester2\\*", &data); 

Dadurch wird die gesamte Liste der Elemente unter dem Verzeichnis aufgelistet. Das Filtern der Verzeichnisse kann auf folgende Weise durchgeführt werden:

if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
// directory
}
else
{
// file
}

Folgendes kann für Referenzen verwendet werden: FileAttributes-Konstanten , FIND_DATA struct , FindFirstFile-API

0
papadp