c# - Bessere Möglichkeit, zu überprüfen, ob ein Pfad eine Datei oder ein Verzeichnis ist?


Ich verarbeite eine TreeView von Verzeichnissen und Dateien. Ein Benutzer kann entweder eine Datei oder ein Verzeichnis auswählen und dann etwas damit machen. Dies erfordert eine Methode, die basierend auf der Auswahl des Benutzers verschiedene Aktionen ausführt.

Im Moment mache ich so etwas um festzustellen, ob der Pfad eine Datei oder ein Verzeichnis ist:

bool bIsFile = false;
bool bIsDirectory = false;

try
{
    string[] subfolders = Directory.GetDirectories(strFilePath);

    bIsDirectory = true;
    bIsFile = false;
}
catch(System.IO.IOException)
{
    bIsFolder = false;
    bIsFile = true;
}

Ich kann nicht umhin zu fühlen, dass es einen besseren Weg gibt, dies zu tun! Ich hoffte, eine Standard-.NET-Methode zu finden, mit der ich das umgehen konnte, aber ich war nicht in der Lage, dies zu tun. Gibt es eine solche Methode, und wenn nicht, was ist das einfachste Mittel, um festzustellen, ob ein Pfad eine Datei oder ein Verzeichnis ist?



Answers


Von Wie man sagt, ob der Pfad eine Datei oder ein Verzeichnis ist :

// get the file attributes for file or directory
FileAttributes attr = File.GetAttributes(@"c:\Temp");

//detect whether its a directory or file
if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
    MessageBox.Show("Its a directory");
else
    MessageBox.Show("Its a file");

Update für .NET 4.0+

In den folgenden Kommentaren können Sie den Code sauberer schreiben, wenn Sie .NET 4.0 oder höher verwenden (und die maximale Leistung nicht kritisch ist):

// get the file attributes for file or directory
FileAttributes attr = File.GetAttributes(@"c:\Temp");

if (attr.HasFlag(FileAttributes.Directory))
    MessageBox.Show("Its a directory");
else
    MessageBox.Show("Its a file");



Wie wäre es mit diesen?

File.Exists();
Directory.Exists();



Mit nur dieser Zeile können Sie erhalten, wenn ein Pfad ein Verzeichnis oder eine Datei ist:

File.GetAttributes(data.Path).HasFlag(FileAttributes.Directory)



Der genaueste Ansatz wird Interop-Code aus der Datei shlwapi.dll verwenden.

[DllImport(SHLWAPI, CharSet = CharSet.Unicode)]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
[ResourceExposure(ResourceScope.None)]
internal static extern bool PathIsDirectory([MarshalAsAttribute(UnmanagedType.LPWStr), In] string pszPath);

Sie würden es dann so nennen:

#region IsDirectory
/// <summary>
/// Verifies that a path is a valid directory.
/// </summary>
/// <param name="path">The path to verify.</param>
/// <returns><see langword="true"/> if the path is a valid directory; 
/// otherwise, <see langword="false"/>.</returns>
/// <exception cref="T:System.ArgumentNullException">
/// <para><paramref name="path"/> is <see langword="null"/>.</para>
/// </exception>
/// <exception cref="T:System.ArgumentException">
/// <para><paramref name="path"/> is <see cref="F:System.String.Empty">String.Empty</see>.</para>
/// </exception>
public static bool IsDirectory(string path)
{
    return PathIsDirectory(path);
}



Alternativ zu Directory.Exists () können Sie die File.GetAttributes () -Methode verwenden, um die Attribute einer Datei oder eines Verzeichnisses abzurufen, damit Sie eine solche Hilfsmethode erstellen können:

private static bool IsDirectory(string path)
{
    System.IO.FileAttributes fa = System.IO.File.GetAttributes(path);
    bool isDirectory = false;
    if ((fa & FileAttributes.Directory) != 0)
    {
        isDirectory = true;
    }
    return isDirectory;
}

Sie können auch ein Objekt zur Tag-Eigenschaft des TreeView-Steuerelements hinzufügen, wenn Sie das Steuerelement auffüllen, das zusätzliche Metadaten für das Element enthält. Sie könnten beispielsweise ein FileInfo-Objekt für Dateien und ein DirectoryInfo-Objekt für Verzeichnisse hinzufügen und dann den Objekttyp in der Tag-Eigenschaft testen, um zusätzliche Systemaufrufe zu speichern, um diese Daten beim Klicken auf das Element abzurufen.




Das war das Beste, was ich angesichts des Verhaltens der Eigenschaften Exists und Attribute herausfinden konnte:

using System.IO;

public static class FileSystemInfoExtensions
{
    /// <summary>
    /// Checks whether a FileInfo or DirectoryInfo object is a directory, or intended to be a directory.
    /// </summary>
    /// <param name="fileSystemInfo"></param>
    /// <returns></returns>
    public static bool IsDirectory(this FileSystemInfo fileSystemInfo)
    {
        if (fileSystemInfo == null)
        {
            return false;
        }

        if ((int)fileSystemInfo.Attributes != -1)
        {
            // if attributes are initialized check the directory flag
            return fileSystemInfo.Attributes.HasFlag(FileAttributes.Directory);
        }

        // If we get here the file probably doesn't exist yet.  The best we can do is 
        // try to judge intent.  Because directories can have extensions and files
        // can lack them, we can't rely on filename.
        // 
        // We can reasonably assume that if the path doesn't exist yet and 
        // FileSystemInfo is a DirectoryInfo, a directory is intended.  FileInfo can 
        // make a directory, but it would be a bizarre code path.

        return fileSystemInfo is DirectoryInfo;
    }
}

So testet es:

    [TestMethod]
    public void IsDirectoryTest()
    {
        // non-existing file, FileAttributes not conclusive, rely on type of FileSystemInfo
        const string nonExistentFile = @"C:\TotallyFakeFile.exe";

        var nonExistentFileDirectoryInfo = new DirectoryInfo(nonExistentFile);
        Assert.IsTrue(nonExistentFileDirectoryInfo.IsDirectory());

        var nonExistentFileFileInfo = new FileInfo(nonExistentFile);
        Assert.IsFalse(nonExistentFileFileInfo.IsDirectory());

        // non-existing directory, FileAttributes not conclusive, rely on type of FileSystemInfo
        const string nonExistentDirectory = @"C:\FakeDirectory";

        var nonExistentDirectoryInfo = new DirectoryInfo(nonExistentDirectory);
        Assert.IsTrue(nonExistentDirectoryInfo.IsDirectory());

        var nonExistentFileInfo = new FileInfo(nonExistentDirectory);
        Assert.IsFalse(nonExistentFileInfo.IsDirectory());

        // Existing, rely on FileAttributes
        const string existingDirectory = @"C:\Windows";

        var existingDirectoryInfo = new DirectoryInfo(existingDirectory);
        Assert.IsTrue(existingDirectoryInfo.IsDirectory());

        var existingDirectoryFileInfo = new FileInfo(existingDirectory);
        Assert.IsTrue(existingDirectoryFileInfo.IsDirectory());

        // Existing, rely on FileAttributes
        const string existingFile = @"C:\Windows\notepad.exe";

        var existingFileDirectoryInfo = new DirectoryInfo(existingFile);
        Assert.IsFalse(existingFileDirectoryInfo.IsDirectory());

        var existingFileFileInfo = new FileInfo(existingFile);
        Assert.IsFalse(existingFileFileInfo.IsDirectory());
    }



Hier ist meins:

    bool IsPathDirectory(string path)
    {
        if (path == null) throw new ArgumentNullException("path");
        path = path.Trim();

        if (Directory.Exists(path)) 
            return true;

        if (File.Exists(path)) 
            return false;

        // neither file nor directory exists. guess intention

        // if has trailing slash then it's a directory
        if (new[] {"\\", "/"}.Any(x => path.EndsWith(x)))
            return true; // ends with slash

        // if has extension then its a file; directory otherwise
        return string.IsNullOrWhiteSpace(Path.GetExtension(path));
    }

Es ist ähnlich wie andere Antworten, aber nicht genau das gleiche.




Ich bin auf ein ähnliches Problem gestoßen, außer dass ich überprüfen musste, ob ein Pfad für eine Datei oder einen Ordner ist, wenn diese Datei oder dieser Ordner nicht existiert . Es gab einige Kommentare zu den obigen Antworten, die besagten, dass sie für dieses Szenario nicht funktionieren würden. Ich habe eine Lösung gefunden (ich benutze VB.NET, aber Sie können konvertieren, wenn Sie brauchen), das scheint gut für mich zu funktionieren:

Dim path As String = "myFakeFolder\ThisDoesNotExist\"
Dim bIsFolder As Boolean = (IO.Path.GetExtension(path) = "")
'returns True

Dim path As String = "myFakeFolder\ThisDoesNotExist\File.jpg"
Dim bIsFolder As Boolean = (IO.Path.GetExtension(path) = "")
'returns False

Hoffentlich kann das jemandem helfen!




Soooo spät im Spiel weiß ich, aber dachte, ich würde das trotzdem teilen. Wenn Sie ausschließlich mit Strings arbeiten, ist das einfach:

private bool IsFolder(string ThePath)
{
    string BS = Path.DirectorySeparatorChar.ToString();
    return Path.GetDirectoryName(ThePath) == ThePath.TrimEnd(BS.ToCharArray());
}

Zum Beispiel: ThePath == "C:\SomeFolder\File1.txt" würde am Ende so ThePath == "C:\SomeFolder\File1.txt" :

return "C:\SomeFolder" == "C:\SomeFolder\File1.txt" (FALSE)

Ein anderes Beispiel: ThePath == "C:\SomeFolder\" würde dies sein:

return "C:\SomeFolder" == "C:\SomeFolder" (TRUE)

Und dies würde auch ohne den folgenden ThePath == "C:\SomeFolder" Schrägstrich ThePath == "C:\SomeFolder" : ThePath == "C:\SomeFolder" würde am Ende so ThePath == "C:\SomeFolder" :

return "C:\SomeFolder" == "C:\SomeFolder" (TRUE)

Denken Sie daran, dass dies nur mit den Pfaden selbst funktioniert, und nicht mit der Beziehung zwischen dem Pfad und der "physischen Festplatte" ... daher kann es Ihnen nicht sagen, ob der Pfad / die Datei existiert oder etwas ähnliches, aber es ist sicher kann Ihnen sagen, ob der Pfad ein Ordner oder eine Datei ist ...




Hier ist was wir verwenden:

using System;

using System.IO;

namespace crmachine.CommonClasses
{

  public static class CRMPath
  {

    public static bool IsDirectory(string path)
    {
      if (path == null)
      {
        throw new ArgumentNullException("path");
      }

      string reason;
      if (!IsValidPathString(path, out reason))
      {
        throw new ArgumentException(reason);
      }

      if (!(Directory.Exists(path) || File.Exists(path)))
      {
        throw new InvalidOperationException(string.Format("Could not find a part of the path '{0}'",path));
      }

      return (new System.IO.FileInfo(path).Attributes & FileAttributes.Directory) == FileAttributes.Directory;
    } 

    public static bool IsValidPathString(string pathStringToTest, out string reasonForError)
    {
      reasonForError = "";
      if (string.IsNullOrWhiteSpace(pathStringToTest))
      {
        reasonForError = "Path is Null or Whitespace.";
        return false;
      }
      if (pathStringToTest.Length > CRMConst.MAXPATH) // MAXPATH == 260
      {
        reasonForError = "Length of path exceeds MAXPATH.";
        return false;
      }
      if (PathContainsInvalidCharacters(pathStringToTest))
      {
        reasonForError = "Path contains invalid path characters.";
        return false;
      }
      if (pathStringToTest == ":")
      {
        reasonForError = "Path consists of only a volume designator.";
        return false;
      }
      if (pathStringToTest[0] == ':')
      {
        reasonForError = "Path begins with a volume designator.";
        return false;
      }

      if (pathStringToTest.Contains(":") && pathStringToTest.IndexOf(':') != 1)
      {
        reasonForError = "Path contains a volume designator that is not part of a drive label.";
        return false;
      }
      return true;
    }

    public static bool PathContainsInvalidCharacters(string path)
    {
      if (path == null)
      {
        throw new ArgumentNullException("path");
      }

      bool containedInvalidCharacters = false;

      for (int i = 0; i < path.Length; i++)
      {
        int n = path[i];
        if (
            (n == 0x22) || // "
            (n == 0x3c) || // <
            (n == 0x3e) || // >
            (n == 0x7c) || // |
            (n  < 0x20)    // the control characters
          )
        {
          containedInvalidCharacters = true;
        }
      }

      return containedInvalidCharacters;
    }


    public static bool FilenameContainsInvalidCharacters(string filename)
    {
      if (filename == null)
      {
        throw new ArgumentNullException("filename");
      }

      bool containedInvalidCharacters = false;

      for (int i = 0; i < filename.Length; i++)
      {
        int n = filename[i];
        if (
            (n == 0x22) || // "
            (n == 0x3c) || // <
            (n == 0x3e) || // >
            (n == 0x7c) || // |
            (n == 0x3a) || // : 
            (n == 0x2a) || // * 
            (n == 0x3f) || // ? 
            (n == 0x5c) || // \ 
            (n == 0x2f) || // /
            (n  < 0x20)    // the control characters
          )
        {
          containedInvalidCharacters = true;
        }
      }

      return containedInvalidCharacters;
    }

  }

}



Ich verwende das Folgende, es testet auch die Erweiterung, was bedeutet, dass es zum Testen verwendet werden kann, wenn der bereitgestellte Pfad eine Datei ist, aber eine Datei, die nicht existiert.

private static bool isDirectory(string path)
{
    bool result = true;
    System.IO.FileInfo fileTest = new System.IO.FileInfo(path);
    if (fileTest.Exists == true)
    {
        result = false;
    }
    else
    {
        if (fileTest.Extension != "")
        {
            result = false;
        }
    }
    return result;
}



Wenn Sie Verzeichnisse finden wollen, einschließlich solcher, die als "versteckt" und "System" markiert sind, versuchen Sie dies (benötigt .NET V4):

FileAttributes fa = File.GetAttributes(path);
if(fa.HasFlag(FileAttributes.Directory)) 



using System;
using System.IO;
namespace FileOrDirectory
{
     class Program
     {
          public static string FileOrDirectory(string path)
          {
               if (File.Exists(path))
                    return "File";
               if (Directory.Exists(path))
                    return "Directory";
               return "Path Not Exists";
          }
          static void Main()
          {
               Console.WriteLine("Enter The Path:");
               string path = Console.ReadLine();
               Console.WriteLine(FileOrDirectory(path));
          }
     }
}



Ich brauchte das, die Pfosten geholfen, dieses erhält es zu einer Linie, und wenn der Pfad überhaupt kein Weg ist, gibt es gerade zurück und verlässt die Methode. Es behebt alle oben genannten Bedenken, benötigt aber auch keinen abschließenden Schrägstrich.

if (!Directory.Exists(@"C:\folderName")) return;



Unter Verwendung der ausgewählten Antwort auf diesen Beitrag schaute ich mir die Kommentare an und gab @ ŞafakGür, @Anthony und @Quinn Wilson Glauben für ihre Info-Bits, die mich zu dieser verbesserten Antwort führten, die ich geschrieben und getestet habe:

    /// <summary>
    /// Returns true if the path is a dir, false if it's a file and null if it's neither or doesn't exist.
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static bool? IsDirFile(this string path)
    {
        bool? result = null;

        if(Directory.Exists(path) || File.Exists(path))
        {
            // get the file attributes for file or directory
            var fileAttr = File.GetAttributes(path);

            if (fileAttr.HasFlag(FileAttributes.Directory))
                result = true;
            else
                result = false;
        }

        return result;
    }



Nachdem ich die Vorschläge der anderen Antworten kombiniert hatte, wurde mir klar, dass ich ungefähr das Gleiche wie Ronnie Overbys Antwort gefunden hatte . Hier einige Tests, die auf einige Dinge hinweisen, über die Sie nachdenken sollten:

  1. Ordner können "Erweiterungen" haben: C:\Temp\folder_with.dot
  2. Dateien können nicht mit einem Verzeichnistrennzeichen (Schrägstrich) enden
  3. Es gibt technisch zwei Verzeichnis-Separatoren, die plattformspezifisch sind - dh, möglicherweise Schrägstriche ( Path.DirectorySeparatorChar und Path.AltDirectorySeparatorChar )

Tests (Linqpad)

var paths = new[] {
    // exists
    @"C:\Temp\dir_test\folder_is_a_dir",
    @"C:\Temp\dir_test\is_a_dir_trailing_slash\",
    @"C:\Temp\dir_test\existing_folder_with.ext",
    @"C:\Temp\dir_test\file_thats_not_a_dir",
    @"C:\Temp\dir_test\notadir.txt",
    // doesn't exist
    @"C:\Temp\dir_test\dne_folder_is_a_dir",
    @"C:\Temp\dir_test\dne_folder_trailing_slash\",
    @"C:\Temp\dir_test\non_existing_folder_with.ext",
    @"C:\Temp\dir_test\dne_file_thats_not_a_dir",
    @"C:\Temp\dir_test\dne_notadir.txt",        
};

foreach(var path in paths) {
    IsFolder(path/*, false*/).Dump(path);
}

Ergebnisse

C:\Temp\dir_test\folder_is_a_dir
  True 
C:\Temp\dir_test\is_a_dir_trailing_slash\
  True 
C:\Temp\dir_test\existing_folder_with.ext
  True 
C:\Temp\dir_test\file_thats_not_a_dir
  False 
C:\Temp\dir_test\notadir.txt
  False 
C:\Temp\dir_test\dne_folder_is_a_dir
  True 
C:\Temp\dir_test\dne_folder_trailing_slash\
  True 
C:\Temp\dir_test\non_existing_folder_with.ext
  False (this is the weird one)
C:\Temp\dir_test\dne_file_thats_not_a_dir
  True 
C:\Temp\dir_test\dne_notadir.txt
  False 

Methode

/// <summary>
/// Whether the <paramref name="path"/> is a folder (existing or not); 
/// optionally assume that if it doesn't "look like" a file then it's a directory.
/// </summary>
/// <param name="path">Path to check</param>
/// <param name="assumeDneLookAlike">If the <paramref name="path"/> doesn't exist, does it at least look like a directory name?  As in, it doesn't look like a file.</param>
/// <returns><c>True</c> if a folder/directory, <c>false</c> if not.</returns>
public static bool IsFolder(string path, bool assumeDneLookAlike = true)
{
    // https://.com/questions/1395205/better-way-to-check-if-path-is-a-file-or-a-directory
    // turns out to be about the same as https://.com/a/19596821/1037948

    // check in order of verisimilitude

    // exists or ends with a directory separator -- files cannot end with directory separator, right?
    if (Directory.Exists(path)
        // use system values rather than assume slashes
        || path.EndsWith("" + Path.DirectorySeparatorChar)
        || path.EndsWith("" + Path.AltDirectorySeparatorChar))
        return true;

    // if we know for sure that it's an actual file...
    if (File.Exists(path))
        return false;

    // if it has an extension it should be a file, so vice versa
    // although technically directories can have extensions...
    if (!Path.HasExtension(path) && assumeDneLookAlike)
        return true;

    // only works for existing files, kinda redundant with `.Exists` above
    //if( File.GetAttributes(path).HasFlag(FileAttributes.Directory) ) ...; 

    // no idea -- could return an 'indeterminate' value (nullable bool)
    // or assume that if we don't know then it's not a folder
    return false;
}



Würde das nicht funktionieren?

var isFile = Regex.IsMatch(path, @"\w{1,}\.\w{1,}$");



Dies verwendet DirectoryInfo, um das Attribut zu erhalten

Dim newnode As TreeNode
Dim dirs As New DirectoryInfo(node.FullPath)
For Each dir As DirectoryInfo In dirs.GetDirectories()
    If dir.Attributes = FileAttributes.Directory Then

    Else

    End If
Next

Dies funktioniert, wenn Sie versuchen, durch DirectoryInfo zu gelangen, indem Sie versuchen, eine TreeView zu erstellen oder eine TreeView zu lesen.