.NET Wie prüfe ich, ob der Pfad eine Datei und kein Verzeichnis ist?

76

Ich habe einen Pfad und muss feststellen, ob es sich um ein Verzeichnis oder eine Datei handelt.

Ist dies der beste Weg, um festzustellen, ob der Pfad eine Datei ist?

string file = @"C:\Test\foo.txt";

bool isFile = !System.IO.Directory.Exists(file) && 
                         System.IO.File.Exists(file);

Für ein Verzeichnis würde ich die Logik umkehren.

string directory = @"C:\Test";

bool isDirectory = System.IO.Directory.Exists(directory) && 
                            !System.IO.File.Exists(directory);

Wenn beides nicht existiert, werde ich keinen Zweig machen. Nehmen wir also an, dass beide existieren.

David Basarab
quelle

Antworten:

117

Verwenden:

System.IO.File.GetAttributes(string path)

und prüfen Sie, ob das zurückgegebene FileAttributesErgebnis den Wert enthält FileAttributes.Directory:

bool isDir = (File.GetAttributes(path) & FileAttributes.Directory)
                 == FileAttributes.Directory;
Alnitak
quelle
15
Stellen Sie einfach sicher, dass Sie dies in einem Versuch / Fang tun, da der Pfad möglicherweise nicht einmal existiert.
LBushkin
Was passiert, wenn der Pfad Platzhalter enthält? Ich erhalte ein illegales Zeichenargument, aber was ist, wenn ich Platzhalter verwende und dies ein legitimer Pfad für meine Benutzer ist?
Michael Sheely
1
@MichaelSheely - AFAIK, um mit Platzhaltern umzugehen, müssen Sie Directory.GetFilesmit der Zeichenfolge aufrufen und prüfen, ob das Ergebnis eine Anzahl größer als Null hat. Ein "Pfad mit Platzhaltern" ist kein Pfad . Es ist ein Muster .
ToolmakerSteve
55

Ich denke, dies ist der einfachste Weg, bei dem Sie nur zwei Überprüfungen benötigen:

string file = @"C:\tmp";
if (System.IO.Directory.Exists(file))
{
    // do stuff when file is an existing directory
}
else if (System.IO.File.Exists(file))
{
    // do stuff when file is an existing file
}
Dirk Vollmar
quelle
Ich habe Sie nicht abgelehnt, aber die akzeptierte Antwort ist sicherlich "einfacher" und benötigt nur einen Anruf (nicht zwei).
Christian.K
9
Der Vorteil dieses Ansatzes besteht darin, dass er auch dann funktioniert, wenn im Dateisystem überhaupt kein übereinstimmender Eintrag vorhanden ist (mit anderen Worten, es handelt sich weder um einen Ordner noch um eine Datei). In diesem Sinne ist es "einfacher". Im Übrigen sagte das OP "einen Pfad" und nicht "einen Pfad, von dem bekannt ist, dass er existiert".
Tao
6
Ja, ich denke tatsächlich, dass dies die bessere Antwort ist, wenn Sie nicht sicher sind, ob der Pfad, den Sie untersuchen, vorhanden ist oder nicht. Es ist eine große Sache, sich keine Sorgen um Ausnahmen machen zu müssen.
Ben Collins
1
Ich bin damit einverstanden, dass diese Methode effektiv ist. Ich habe gerade ein kleines Dienstprogramm erstellt, um festzustellen, ob der angegebene Name eine Datei oder ein Verzeichnis ist, und diese Methode hat es extrem einfach gemacht, 1für Verzeichnis, 2Datei und 0Fehler zurückzukehren (z. B. ist der Name ungültig). Das Tool ist winzig (338 Byte Quelle, 3584 Byte kompiliert) und läuft sehr schnell.
Synetech
1
@ TomPadilla: Was genau würden Sie erwarten, wenn der Pfad nicht existiert?
Dirk Vollmar
11

Sie können dies mit einem Interop-Code tun:

    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    [return: MarshalAsAttribute(UnmanagedType.Bool)]
    public static extern bool PathIsDirectory([MarshalAsAttribute(UnmanagedType.LPWStr), In] string pszPath);

Um einige der Kommentare weiter zu verdeutlichen ...

Das Einführen von nicht verwaltetem Code ist nicht gefährlicher als alle anderen Datei- oder E / A-bezogenen Aufrufe in .NET, da letztendlich alle nicht verwalteten Code aufrufen.

Dies ist ein einzelner Funktionsaufruf mit einer Zeichenfolge. Durch Aufrufen dieser Funktion werden keine neuen Datentypen und / oder Speichernutzung eingeführt. Ja, Sie müssen sich auf den nicht verwalteten Code verlassen, um ordnungsgemäß zu bereinigen, aber letztendlich haben Sie diese Abhängigkeit von den meisten E / A-bezogenen Aufrufen.

Als Referenz finden Sie hier den Code für File.GetAttributes (Zeichenfolgenpfad) von Reflector:

public static FileAttributes GetAttributes(string path)
{
    string fullPathInternal = Path.GetFullPathInternal(path);
    new FileIOPermission(FileIOPermissionAccess.Read, new string[] { fullPathInternal }, false, false).Demand();
    Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
    int errorCode = FillAttributeInfo(fullPathInternal, ref data, false, true);
    if (errorCode != 0)
    {
        __Error.WinIOError(errorCode, fullPathInternal);
    }
    return (FileAttributes) data.fileAttributes;
}

Wie Sie sehen können, wird auch nicht verwalteter Code aufgerufen, um die Dateiattribute abzurufen. Daher sind die Argumente zur Einführung von nicht verwaltetem Code, der gefährlich ist, ungültig. Ebenso das Argument, vollständig im verwalteten Code zu bleiben. Hierfür gibt es keine Implementierung von verwaltetem Code. Selbst das Aufrufen von File.GetAttributes (), wie in den anderen Antworten vorgeschlagen, hat die gleichen "Probleme" beim Aufrufen von nicht geändertem Code, und ich glaube, dies ist die zuverlässigere Methode, um festzustellen, ob ein Pfad ein Verzeichnis ist.

Bearbeiten Um den Kommentar von @Christian K zu CAS zu beantworten. Ich glaube, der einzige Grund, warum GetAttributes die Sicherheitsanforderung stellt, ist, dass es die Eigenschaften der Datei lesen muss, um sicherzustellen, dass der aufrufende Code die Berechtigung dazu hat. Dies ist nicht dasselbe wie die zugrunde liegenden Betriebssystemprüfungen (falls vorhanden). Sie können jederzeit eine Wrapper-Funktion um den P / Invoke-Aufruf von PathIsDirectory erstellen, die bei Bedarf auch bestimmte CAS-Berechtigungen erfordert.

Scott Dorman
quelle
3
Das scheint eine Menge Arbeit zu sein, um herauszufinden, ob ein Pfad eine Datei oder ein Verzeichnis ist.
David Basarab
2
Ich verstehe nicht, warum dies abgelehnt wird, obwohl es viel einfacher wäre, im verwalteten Code nur mit .NET-Funktionalität zu bleiben.
Dirk Vollmar
1
Das Einführen von nicht verwaltetem Code, um festzustellen, ob ein Pfad eine Datei oder ein Verzeichnis ist, ist gefährlich. Ich muss die aufrufende Funktion weiterleiten, um den Speicher ordnungsgemäß zu bereinigen, da sonst mein Code undicht werden kann.
David Basarab
1
Ich verstehe immer noch nicht, warum dies herabgestuft wird, da es die Frage mit einer Methode richtig beantwortet, die kein Maß an Mehrdeutigkeit bietet.
Scott Dorman
4
Das ist die "Schönheit" von SO, sogar eine gute Antwort könnte von einigen Eiferern abgelehnt werden;)
Wodzu
7

Angenommen, das Verzeichnis existiert ...

bool isDir = (File.GetAttributes(path) & FileAttributes.Directory)
                  == FileAttributes.Directory;
Tvanfosson
quelle
Wenn der Pfad nicht vorhanden ist, gibt GetAttributes -1 zurück.
Binary Worrier
1
Dokumente scheinen darauf hinzuweisen, dass eine Ausnahme ausgelöst wird, wenn die Datei nicht vorhanden ist. msdn.microsoft.com/en-us/library/…
tvanfosson
4

Überprüfen Sie dies heraus:

/// <summary>
/// Returns true if the given file path is a folder.
/// </summary>
/// <param name="Path">File path</param>
/// <returns>True if a folder</returns>
public bool IsFolder(string path)
{
    return ((File.GetAttributes(path) & FileAttributes.Directory) == FileAttributes.Directory);
}

von http://www.jonasjohn.de/snippets/csharp/is-folder.htm

Dror
quelle
2

Lesen Sie die Dateiattribute:

FileAttributes att = System.IO.File.GetAttributes(PATH_TO_FILE);

Suchen Sie nach dem Verzeichnisflag .

Igor Zelaya
quelle
1

Da eine bestimmte Pfadzeichenfolge nicht sowohl ein Verzeichnis als auch eine Datei darstellen kann, funktioniert das Folgende einwandfrei und öffnet die Tür für andere Vorgänge.

bool isFile = new FileInfo(path).Exists;
bool isDir = new DirectoryInfo(path).Exists;

Wenn Sie mit dem Dateisystem arbeiten, ist die Verwendung von FileInfound DirectoryInfoviel einfacher als die Verwendung von Zeichenfolgen.

Drew Noakes
quelle
Siehe 0xA3s Antwort, etwas bessere Anrufe imo.
Nawfal
Oder nur wenn (Directory.Exists (src)) ... Wenn es sich um eine Datei handelt, ist sie falsch. Wenn src ein Verzeichnis ist, ist es falsch. Wenn src ein Verzeichnis ist, das nicht existiert, kann src per Definition kein Verzeichnis sein.
Chris Bordeman
-3

Hmm, es sieht so aus, als hätte die FilesKlasse (in java.nio) tatsächlich eine statische isDirectoryMethode. Ich denke, Sie könnten tatsächlich Folgendes verwenden:

Path what = ...
boolean isDir = Files.isDirectory(what);
Onikoroshi
quelle
4
Auf der Suche nach einer .NET-Lösung.
David Basarab