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

Lesezeit: 6 Minuten

Benutzeravatar von Zach Burlingame
Zach Burlingame

Frage

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

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

* Ich verstehe, dass Sie in Rennbedingungen geraten können, wenn Sie zwischen dem Zeitpunkt, an dem Sie nach der Existenz suchen, und dem Zeitpunkt, an dem Sie den Pfad verwenden, dass er nicht mehr existiert, aber ich kann damit umgehen.

Zusätzlicher Hintergrund

Explizit zu wissen, ob ein Verzeichnis existiert oder nicht, kann schwierig werden, wenn Berechtigungen ins Spiel kommen. Es ist möglich, dass der Prozess beim Versuch festzustellen, ob das Verzeichnis existiert, keine Berechtigungen zum Zugriff auf das Verzeichnis oder ein übergeordnetes Verzeichnis hat. Das ist für meine Bedürfnisse ok. Wenn das Verzeichnis nicht existiert ODER ich nicht darauf zugreifen kann, wird beides 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, C-Laufzeitbibliothek oder Win32-API ist in Ordnung, aber idealerweise möchte ich mich an Bibliotheken halten, die häufig geladen werden (z. B. Kernel32, User32 usw.) und Lösungen vermeiden, die das Laden von nicht standardmäßigen Bibliotheken beinhalten (wie PathFileExists in Shlwapi.dll). Auch hier gibt es (virtuelle) Bonuspunkte, wenn Ihre Lösung plattformübergreifend ist.

Verwandt

Wie können wir mit dem Win32-Programm überprüfen, ob eine Datei vorhanden ist oder nicht?

  • Was meinst du mit “Ich kann nicht darauf zugreifen”? Lesezugriff? Schreibzugriff? Dateizugriff löschen?

    – Jim Mischel

    2. Juni 2011 um 18:11 Uhr

  • Gute Frage. Dazu lesender Zugriff. Ich würde annehmen (lies: das könnte dumm sein), dass die Überprüfung auf Lesezugriff ausreichen würde, da dann der Versuch, einen Dateizugriff (RWD) in diesem Verzeichnis durchzuführen, zu einem entsprechenden Fehler dieses API-Aufrufs (z. B. CreateFile, WriteFile) führen würde. Wenn Sie jedoch nicht einmal zum Lesen auf das Verzeichnis zugreifen können (entweder weil es nicht existiert oder Sie keine Berechtigungen haben), führt die Verwendung in einem Aufruf von Dateizugriffsfunktionen zu Fehlern, die Sie nicht von Pfadproblemen unterscheiden können.

    – Zach Burlingame

    2. Juni 2011 um 18:32 Uhr

  • In der Windows-API können Sie meiner Meinung nach auch FindFirstFile() verwenden, um die Existenz zu testen. msdn.microsoft.com/en-us/library/windows/desktop/…

    – Gleichgültig

    18. Dezember 2012 um 1:54 Uhr

  • “Allgemein geladene” und “Nicht-Standard”-Bibliotheken schließen sich nicht gegenseitig aus, wie im letzten Absatz angedeutet.

    – Adrian McCarthy

    1. Oktober 2013 um 16:03 Uhr

  • mögliches Duplikat von Wie können wir mit dem Win32-Programm überprüfen, ob eine Datei vorhanden ist oder nicht?

    – Adrian McCarthy

    1. Oktober 2013 um 16:04 Uhr

Benutzeravatar von retrodrone
Retrodrohne

Mach so etwas:

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

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

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

  • Wenn szPath ist "C:\\"GetFileAttributes, PathIsDirectory und PathFileExists funktionieren nicht.

    – zwcloud

    30. Juni 2015 um 7:59 Uhr


  • Ich habe gerade entdeckt, 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 hm.

    – frr

    26. Oktober 2017 um 19:29 Uhr

  • @zwcloud Wo hast du das getestet? GetFileAttributes funktioniert gut für mich.

    – Martin

    19. Februar 2018 um 15:42 Uhr

Benutzeravatar von dario_ramos
dario_ramos

Hier ist eine völlig plattformunabhängige Lösung (unter Verwendung der Standard-C-Bibliothek)

Bearbeiten: Um dies unter Linux zu kompilieren, ersetzen Sie <io.h> mit <unistd.h> und _access mit access. Verwenden Sie für eine wirklich 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;
}

  • Das ist nicht plattformunabhängig oder Standard, das ist Microsofts Nachahmung von POSIX (tatsächlich würden Sie es bekommen access aus <unistd.h> und es würde nicht mit einem Unterstrich beginnen.)

    – asveikau

    2. Juni 2011 um 18:14 Uhr


  • Ooops, mein Fehler. Sie haben Recht, wenn ich nach den #included .h suche, befinden sie sich in einem Visual Studio-Ordner. Eine Sache: Wenn Sie “Imitation” sagen, meinen Sie, dass es nicht wirklich POSIX-konform ist? Wie in … Das würde nicht unter Linux kompiliert werden?

    – dario_ramos

    2. Juni 2011 um 18:20 Uhr


  • Richtig, es ist nicht POSIX, so etwas gibt es nicht io.h oder _access (mit Unterstrich) auf anderen Plattformen.

    – asveikau

    2. Juni 2011 um 18:22 Uhr

  • Ich hatte Probleme mit Schrägstrichen unter Windows mit dieser Lösung, obwohl jeder denkt, Win32 akzeptiert / statt “ überall. Ich bin verwirrt darüber, aber seien Sie anscheinend vorsichtig mit POSIX-Pfaden und POSIX-libc-Funktionen unter Win32.

    – mxkl

    30. Mai 2013 um 11:53 Uhr

  • Ja, wie Asveikau sagte, die Windows-Implementierung von POSIX ist nicht perfekt. Wenn Sie Zugriff auf ein portables Dateisystem wünschen, verwenden Sie Boost (das mache ich gerade).

    – dario_ramos

    30. Mai 2013 um 14:16 Uhr

Wenn die Verknüpfung mit der Shell Lightweight API (shlwapi.dll) für Sie in Ordnung ist, können Sie die PathIsDirectory-Funktion.

Eine weitere Möglichkeit 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.”

Diese Frage ist also voller Grenzfälle. Eine echte Antwort wäre wie folgt:

BOOL DirectoryExists(LPCTSTR szPath, BOOL *exists)
{
  *exists = FALSE;
  size_t szLen = _tcslen(szPath);
  if (szLen > 0 && szPath[szLen - 1] == '\\') --szLen;
  HANDLE heap = GetProcessHeap();
  LPCTSTR szPath2 = HeapAlloc(heap, 0, (szlen + 3) * sizeof(TCHAR));
  if (!szPath2) return FALSE;
  CopyMemory(szPath2, szPath, szLen * sizeof(TCHAR));
  szPath2[szLen] = '\\';
  szPath2[szLen + 1] = '.';
  szPath2[szLen + 2] = 0;
  DWORD dwAttrib = GetFileAttributes(szPath2);
  HeapFree(heap, 0, szPath2);

  if (dwAttrib != INVALID_FILE_ATTRIBUTES) {
    *exists = TRUE; /* no point checking FILE_ATTRIBUTE_DIRECTORY on "." */
    return TRUE;
  }
  /*
   * If we get anything other than ERROR_PATH_NOT_FOUND then something's wrong.
   * Could be hardware IO, lack of permissions, a symbolic link pointing to somewhere
   * you don't have access, etc.
   */
  return GetLastError() != ERROR_PATH_NOT_FOUND;
}

Das korrekte Ergebnis von DirectoryExists ist Tri-State. Es gibt drei Fälle und Sie müssen alle behandeln. Entweder existiert es, es existiert nicht, oder Sie konnten es nicht überprüfen. Ich habe Daten in der Produktion verloren, weil ein SAN NEIN an die Prüffunktion zurückgab und mich dann etwas erstellen ließ, das sie in der nächsten Codezeile überfiel. Machen Sie nicht den gleichen Fehler, den Microsoft beim Entwerfen von gemacht hat File.Exists() API in C#.

Ich sehe jedoch viele Schecks, die supliferous sind. Schreiben Sie keine Gedanken wie if (Verzeichnis existiert nicht) CreateDirectory(); einfach schreiben CreateDirectory() if (GetLastError() != 0 && GetLastError() != ERROR_ALREADY_EXISTS. Oder umgekehrt mit RemoveDirectory(); Entfernen Sie es einfach und prüfen Sie, ob kein Fehler vorliegt oder ob der Pfad nicht gefunden wurde.

1417590cookie-checkWie überprüfen Sie, ob ein Verzeichnis unter Windows in C vorhanden ist?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy