c# - Meilleur moyen de vérifier si un chemin est un fichier ou un répertoire?


Je suis en TreeView de traiter un TreeView de répertoires et de fichiers. Un utilisateur peut sélectionner un fichier ou un répertoire, puis faire quelque chose avec. Cela nécessite de disposer d'une méthode qui effectue différentes actions en fonction de la sélection de l'utilisateur.

En ce moment je fais quelque chose comme ceci pour déterminer si le chemin est un fichier ou un répertoire:

bool bIsFile = false;
bool bIsDirectory = false;

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

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

Je ne peux pas aider à sentir qu'il y a une meilleure façon de le faire! J'espérais trouver une méthode standard .NET pour gérer cela, mais je n'ai pas été en mesure de le faire. Est-ce qu'une telle méthode existe, et sinon, quel est le moyen le plus simple pour déterminer si un chemin est un fichier ou un répertoire?


Answers



De Comment savoir si le chemin est un fichier ou un répertoire :

// 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");

Mise à jour pour .NET 4.0+

Selon les commentaires ci-dessous, si vous êtes sur .NET 4.0 ou version ultérieure (et que les performances maximales ne sont pas critiques), vous pouvez écrire le code de manière plus propre:

// 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");



Pourquoi ne pas les utiliser?

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



Avec seulement cette ligne vous pouvez obtenir si un chemin est un répertoire ou un fichier:

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



L'approche la plus précise va utiliser un code d'interopérabilité du fichier shlwapi.dll

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

Vous l'appelleriez alors comme ceci:

#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);
}



Comme alternative à Directory.Exists (), vous pouvez utiliser la méthode File.GetAttributes () pour obtenir les attributs d'un fichier ou d'un répertoire, ainsi vous pouvez créer une méthode d'assistance comme ceci:

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;
}

Vous pouvez également envisager d'ajouter un objet à la propriété tag du contrôle TreeView lors du remplissage du contrôle contenant des métadonnées supplémentaires pour l'élément. Par exemple, vous pouvez ajouter un objet FileInfo pour les fichiers et un objet DirectoryInfo pour les répertoires, puis tester le type d'élément dans la propriété tag pour enregistrer des appels système supplémentaires pour obtenir ces données lorsque vous cliquez sur l'élément.




C'était le meilleur que je pouvais trouver étant donné le comportement des propriétés Exists et Attributes:

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;
    }
}

Voici comment ça se passe:

    [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());
    }



Voici la mienne:

    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));
    }

C'est semblable aux réponses des autres, mais pas exactement la même chose.




Je suis tombé sur ceci en faisant face à un problème semblable, excepté que j'ai dû vérifier si un chemin est pour un dossier ou un dossier quand ce dossier ou dossier peut n'exister pas réellement . Il y avait quelques commentaires sur les réponses ci-dessus qui ont mentionné qu'ils ne fonctionneraient pas pour ce scénario. J'ai trouvé une solution (j'utilise VB.NET, mais vous pouvez convertir si vous avez besoin) qui semble bien fonctionner pour moi:

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

J'espère que cela peut être utile à quelqu'un!




si tard dans le jeu, je sais, mais j'ai pensé que je partagerais ça quand même. Si vous travaillez uniquement avec les chemins en tant que chaînes de caractères, il est facile de comprendre cela:

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

par exemple: ThePath == "C:\SomeFolder\File1.txt" finirait par être ceci:

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

Un autre exemple: ThePath == "C:\SomeFolder\" finirait par être ceci:

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

Et cela fonctionnerait aussi sans backslash: ThePath == "C:\SomeFolder" finirait par être ceci:

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

Gardez à l'esprit ici que cela ne fonctionne qu'avec les chemins eux-mêmes, et non la relation entre le chemin et le "disque physique" ... donc il ne peut pas vous dire si le chemin / fichier existe ou quelque chose comme ça, mais c'est sûr peut vous dire si le chemin est un dossier ou un fichier ...




Voici ce que nous utilisons:

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;
    }

  }

}



J'utilise ce qui suit, il teste aussi l'extension ce qui signifie qu'il peut être utilisé pour tester si le chemin fourni est un fichier mais un fichier qui n'existe pas.

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;
}



Si vous voulez trouver des répertoires, y compris ceux qui sont marqués "caché" et "système", essayez ceci (nécessite .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));
          }
     }
}



J'avais besoin de ceci, les messages aidés, cela descend à une ligne, et si le chemin n'est pas un chemin du tout, il revient juste et quitte la méthode. Il répond à toutes les préoccupations ci-dessus, n'a pas besoin de la barre oblique finale non plus.

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



En utilisant la réponse sélectionnée sur ce post, j'ai regardé les commentaires et donné de la crédibilité à @ ŞafakGür, @Anthony et @Quinn Wilson pour leurs infos qui m'ont conduit à cette réponse améliorée que j'ai écrite et testée:

    /// <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;
    }



Après avoir combiné les suggestions des autres réponses, j'ai réalisé que j'avais trouvé à peu près la même chose que la réponse de Ronnie Overby . Voici quelques tests pour souligner certaines choses à penser:

  1. les dossiers peuvent avoir des "extensions": C:\Temp\folder_with.dot
  2. les fichiers ne peuvent pas se terminer avec un séparateur de répertoire (barre oblique)
  3. Techniquement, il existe deux séparateurs de répertoires spécifiques à la plate-forme, c'est-à-dire qui peuvent être ou non des barres obliques ( Path.DirectorySeparatorChar et 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);
}

Résultats

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 

Méthode

/// <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;
}



Cela ne fonctionnerait-il pas?

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



Ceci utilise DirectoryInfo pour obtenir l'attribut

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

Cela fonctionnera si vous essayez de parcourir DirectoryInfo en essayant de créer un TreeView ou de lire un TreeView