web-dev-qa-db-fra.com

Meilleure façon de vérifier si un chemin est un fichier ou un répertoire?

Je traite une 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 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 m'empêcher de penser qu'il existe un meilleur moyen de le faire! J'espérais trouver une méthode .NET standard pour gérer cela, mais je n'ai pas été capable de le faire. Une telle méthode existe-t-elle et, dans la négative, quel est le moyen le plus simple de déterminer si un chemin est un fichier ou un répertoire?

347
SnAzBaZ

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 utilisez .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");
536
Quinn Wilson

Que diriez-vous de les utiliser?

File.Exists();
Directory.Exists();
228
llamaoo7

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

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

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

Cela ressemble aux réponses des autres mais pas exactement la même chose.

9
Ronnie Overby

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

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

Vous pouvez également envisager d'ajouter un objet à la propriété de balise 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 permettant d'obtenir ces données lorsque vous cliquez sur l'élément.

6

C'était le mieux 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 il teste:

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

Après avoir combiné les suggestions des autres réponses, je me suis rendu compte que j'avais proposé à peu près la même chose que réponse de Ronnie Overby . Voici quelques tests pour souligner quelques points à prendre en compte:

  1. les dossiers peuvent avoir des "extensions": C:\Temp\folder_with.dot
  2. les fichiers ne peuvent pas se terminer par un séparateur de répertoire (barre oblique)
  3. Il existe techniquement deux séparateurs de répertoires qui sont spécifiques à la plate-forme - c’est-à-dire qu’ils peuvent ou non être 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://stackoverflow.com/questions/1395205/better-way-to-check-if-path-is-a-file-or-a-directory
    // turns out to be about the same as https://stackoverflow.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;
}
5
drzaus

L’approche la plus précise consiste à utiliser du code d’interopérabilité à partir du 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);
}
4
Scott Dorman

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

  }

}
2
PMBottas

Je suis tombé sur ce problème face à un problème similaire, sauf que je devais vérifier si un chemin d'accès correspond à un fichier ou à un dossier lorsque ce fichier ou ce dossier n'existe peut-être pas. Quelques commentaires sur les réponses ci-dessus ont indiqué qu'ils ne fonctionneraient pas avec ce scénario. J'ai trouvé une solution (j'utilise VB.NET, mais vous pouvez convertir si vous en 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!

2
lhan

soooo tard dans le jeu je sais, mais je pensais partager cela quand même. Si vous travaillez uniquement avec les chemins en tant que chaînes, 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 la barre oblique inversée: 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 pas la relation entre le chemin et le "disque physique" ... afin qu'il ne puisse 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 ...

2
MaxOvrdrv

Si vous voulez trouver des répertoires, y compris ceux qui sont marqués "caché" et "système", essayez ceci (requiert .NET V4):

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

Je vois, je suis 10 ans trop tard pour la fête. Je faisais face à la situation, où de la propriété je peux recevoir un nom de fichier ou un chemin de fichier complet. Si aucun chemin n'est fourni, je dois vérifier l'existence du fichier en attachant un chemin de répertoire "global" fourni par une autre propriété.

Dans mon cas

var isFileName = System.IO.Path.GetFileName (str) == str;

a fait le tour. Ok, ce n’est pas magique, mais peut-être que cela pourrait sauver quelques minutes à quelqu'un. Comme il s’agit simplement d’une analyse syntaxique de chaînes, les noms de répertoires avec des points peuvent donner des faux positifs ...

0
dba

J'avais besoin de ça, les posts aidés, cela le ramène à une ligne, et si le chemin n'est pas du tout un chemin, il retourne et quitte la méthode. Il répond à toutes les préoccupations ci-dessus, n'a pas besoin de la barre oblique non plus.

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

J'utilise ce qui suit, il teste également 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;
}
0
Stu1983

En utilisant la réponse sélectionnée sur ce message, j’ai examiné les commentaires et crédité les @ ŞafakGür, @Anthony et @Quinn Wilson pour leurs informations qui m’amènent à 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;
    }
0
Mike Socha III

Peut-être pour UWP C #

public static async Task<IStorageItem> AsIStorageItemAsync(this string iStorageItemPath)
    {
        if (string.IsNullOrEmpty(iStorageItemPath)) return null;
        IStorageItem storageItem = null;
        try
        {
            storageItem = await StorageFolder.GetFolderFromPathAsync(iStorageItemPath);
            if (storageItem != null) return storageItem;
        } catch { }
        try
        {
            storageItem = await StorageFile.GetFileFromPathAsync(iStorageItemPath);
            if (storageItem != null) return storageItem;
        } catch { }
        return storageItem;
    }
0
Minute V
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));
          }
     }
}
0
Diaa Eddin