Wie überprüfen Sie, ob unter Windows in C ein Verzeichnis vorhanden ist?

73

Frage

In einer Windows C-Anwendung möchte ich einen an eine Funktion übergebenen Parameter überprüfen, um sicherzustellen, dass der angegebene Pfad vorhanden ist. *

Wie überprüfen Sie, ob unter Windows in C ein Verzeichnis vorhanden ist?

* Ich verstehe, dass Sie in Rennbedingungen geraten können, in denen zwischen der Zeit, in der Sie die Existenz überprüfen, und der Zeit, in der Sie den Pfad verwenden, der nicht mehr existiert, aber ich kann damit umgehen.

Zusätzlicher Hintergrund

Wenn Sie explizit wissen, dass ein Verzeichnis vorhanden ist oder nicht, kann es schwierig werden, wenn Berechtigungen ins Spiel kommen. Es ist möglich, dass der Prozess beim Versuch, festzustellen, ob das Verzeichnis vorhanden ist, keine Berechtigungen zum Zugriff auf das Verzeichnis oder ein übergeordnetes Verzeichnis hat. Dies ist in Ordnung für meine Bedürfnisse . Wenn das Verzeichnis nicht vorhanden ist oder ich nicht darauf zugreifen kann, werden beide in meiner Anwendung als ungültiger Pfadfehler behandelt, sodass ich nicht unterscheiden muss. (Virtuelle) Bonuspunkte, wenn Ihre Lösung diese Unterscheidung vorsieht.

Jede Lösung in der C-Sprache, der C-Laufzeitbibliothek oder der Win32-API ist in Ordnung, aber im Idealfall möchte ich mich an häufig geladene Bibliotheken halten (z. B. Kernel32, User32 usw.) und Lösungen vermeiden, bei denen nicht standardmäßige Bibliotheken geladen werden (wie PathFileExists in Shlwapi.dll). Wieder (virtuelle) Bonuspunkte, wenn Ihre Lösung plattformübergreifend ist.

verbunden

Wie können wir überprüfen, ob eine Datei vorhanden ist oder nicht, indem Sie das Win32-Programm verwenden?

Zach Burlingame
quelle
1
Was meinst du mit "Ich kann nicht darauf zugreifen"? Lesezugriff? Schreibzugriff? Dateizugriff löschen?
Jim Mischel
Gute Frage. Lesen Sie zu diesem Zweck den Zugriff. Ich würde annehmen (lesen: das könnte dumm sein), dass die Überprüfung auf Lesezugriff ausreichen würde, da der Versuch, einen Dateizugriff (RWD) in diesem Verzeichnis durchzuführen, zu einem entsprechenden Fehler dieses API-Aufrufs führt (z. B. CreateFile, WriteFile). Wenn Sie jedoch nicht einmal zum Lesen auf das Verzeichnis zugreifen können (entweder weil es nicht vorhanden ist oder Sie keine Dauerwellen haben), führt die Verwendung in einem Aufruf der Dateizugriffsfunktionen zu Fehlern, die Sie nicht von Pfadproblemen unterscheiden können.
Zach Burlingame
Ich denke, Sie können in der Windows-API auch FindFirstFile () verwenden, um die Existenz zu testen. msdn.microsoft.com/en-us/library/windows/desktop/…
Indinfer
"Häufig geladene" und "nicht standardmäßige" Bibliotheken schließen sich nicht gegenseitig aus, wie im letzten Absatz vorgeschlagen.
Adrian McCarthy

Antworten:

99

Mach so etwas:

BOOL DirectoryExists(LPCTSTR szPath)
{
  DWORD dwAttrib = GetFileAttributes(szPath);

  return (dwAttrib != INVALID_FILE_ATTRIBUTES && 
         (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}

Die GetFileAttributes () -Methode ist in Kernel32.dll enthalten.

Retrodrone
quelle
3
Wenn szPath aktiviert ist "C:\\", funktionieren GetFileAttributes, PathIsDirectory und PathFileExists nicht.
Zwcloud
Ich habe gerade festgestellt, dass GetFileAttributes () einige virtuelle COM-Ports nicht sehen kann, die ansonsten für CreateFile () perfekt verfügbar sind. Trotz der Tatsache, dass FILE_ATTRIBUTE_DEVICE in den Header-Dateien vorhanden ist. Ho hum.
vom
@zwcloud Wo hast du das getestet? GetFileAttributes funktioniert gut für mich.
Martin
23

Hier ist eine vollständig plattformunabhängige Lösung (unter Verwendung der Standard-C-Bibliothek).

Bearbeiten: Damit dies unter Linux kompiliert werden kann, ersetzen Sie es <io.h>durch <unistd.h>und _accessdurch access. Verwenden Sie für eine echte plattformunabhängige Lösung die Boost FileSystem-Bibliothek.

#include <io.h>     // For access().
#include <sys/types.h>  // For stat().
#include <sys/stat.h>   // For stat().

bool DirectoryExists( const char* absolutePath ){

    if( _access( absolutePath, 0 ) == 0 ){

        struct stat status;
        stat( absolutePath, &status );

        return (status.st_mode & S_IFDIR) != 0;
    }
    return false;
}

Eine Windows-spezifische Implementierung, die sowohl MBCS- als auch UNICODE-Builds unterstützt:

#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <tchar.h>

BOOL directory_exists( LPCTSTR absolutePath )
{
  if( _taccess_s( absolutePath, 0 ) == 0 )
  {
    struct _stat status;
    _tstat( absolutePath, &status );
    return (status.st_mode & S_IFDIR) != 0;
  }

  return FALSE;
}
dario_ramos
quelle
5
Das ist nicht plattformunabhängig oder Standard, das ist Microsofts Nachahmung von POSIX (in Wirklichkeit würden Sie bekommen accessaus <unistd.h>und es wäre nicht mit einem Unterstrich beginnen.)
asveikau
Hoppla, mein Schlechtes. Sie haben Recht, wenn ich die #included .hs suche, befinden sie sich in einem Visual Studio-Ordner. Eine Sache: Wenn Sie "Nachahmung" sagen, meinen Sie, dass es nicht wirklich POSIX-konform ist? Wie in ... Dies würde unter Linux nicht kompiliert werden?
dario_ramos
2
Richtig, es ist nicht POSIX, es gibt kein io.hoder _access(mit Unterstrich) auf anderen Plattformen.
Asveikau
1
Ich hatte Probleme mit Schrägstrichen unter Windows mit dieser Lösung, obwohl jeder denkt, dass Win32 akzeptiert, /anstatt überall. Ich bin verwirrt, aber anscheinend seien Sie vorsichtig mit POSIX-Pfaden und POSIX libc-Funktionen unter Win32.
mxcl
Ja, wie Asveikau sagte, ist die Windows-Implementierung von POSIX nicht perfekt. Wenn Sie auf ein tragbares Dateisystem zugreifen möchten, verwenden Sie Boost (das mache ich jetzt).
dario_ramos
4

Eine weitere Option ist die Shell-Funktion PathFileExists ()

PathFileExists () -Dokumentation

Diese Funktion "Bestimmt, ob ein Pfad zu einem Dateisystemobjekt wie einer Datei oder einem Verzeichnis gültig ist."

Greg
quelle