Melhor maneira de verificar se um caminho é um arquivo ou um diretório?

Estou processando um TreeView de diretórios e arquivos. Um usuário pode selecionar um arquivo ou um diretório e, em seguida, fazer algo com ele. Isso requer que eu tenha um método que execute ações diferentes com base na seleção do usuário.

No momento estou fazendo algo assim para determinar se o caminho é um arquivo ou um diretório:

 bool bIsFile = false; bool bIsDirectory = false; try { string[] subfolders = Directory.GetDirectories(strFilePath); bIsDirectory = true; bIsFile = false; } catch(System.IO.IOException) { bIsFolder = false; bIsFile = true; } 

Não posso deixar de sentir que existe uma maneira melhor de fazer isso! Eu estava esperando encontrar um método .NET padrão para lidar com isso, mas não consegui fazer isso. Existe tal método, e se não, qual é o meio mais direto para determinar se um caminho é um arquivo ou diretório?

De como saber se o caminho é um arquivo ou diretório :

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

Atualização para o .NET 4.0+

Pelos comentários abaixo, se você está no .NET 4.0 ou posterior (e o desempenho máximo não é crítico), você pode escrever o código de uma maneira mais limpa:

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

Que tal usar isso?

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

Com apenas esta linha você pode obter se um caminho é um diretório ou um arquivo:

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

Aqui está o meu:

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

É semelhante às respostas dos outros, mas não exatamente o mesmo.

Como uma alternativa para Directory.Exists (), você pode usar o método File.GetAttributes () para obter os atributos de um arquivo ou diretório, para poder criar um método auxiliar como este:

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

Você também pode considerar adicionar um object à propriedade de marca do controle TreeView ao preencher o controle que contém metadados adicionais para o item. Por exemplo, você poderia adicionar um object FileInfo para arquivos e um object DirectoryInfo para diretórios e, em seguida, testar o tipo de item na propriedade tag para salvar chamadas adicionais do sistema para obter esses dados ao clicar no item.

Isso foi o melhor que consegui, dado o comportamento das propriedades Exists e Attributes:

 using System.IO; public static class FileSystemInfoExtensions { ///  /// Checks whether a FileInfo or DirectoryInfo object is a directory, or intended to be a directory. ///  ///  ///  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; } } 

Veja como isso é testado:

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

A abordagem mais precisa será usar algum código de interoperabilidade do 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); 

Você então chamaria assim:

 #region IsDirectory ///  /// Verifies that a path is a valid directory. ///  /// The path to verify. ///  if the path is a valid directory; /// otherwise, . ///  ///  is . ///  ///  ///  is String.Empty. ///  public static bool IsDirectory(string path) { return PathIsDirectory(path); } 

Aqui está o que usamos:

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

Eu me deparei com isso quando enfrento um problema semelhante, exceto que eu precisava verificar se um caminho é para um arquivo ou pasta quando esse arquivo ou pasta não pode realmente existir . Houve alguns comentários sobre as respostas acima mencionadas que eles não funcionariam para esse cenário. Eu encontrei uma solução (eu uso VB.NET, mas você pode converter se precisar) que parece funcionar bem para mim:

 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 

Espero que isso possa ser útil para alguém!

muuuito tarde no jogo eu sei, mas pensei em compartilhar isso de qualquer maneira. Se você estiver trabalhando apenas com os caminhos como strings, descobrir isso é fácil:

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

Por exemplo: ThePath == "C:\SomeFolder\File1.txt" acabaria sendo este:

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

Outro exemplo: ThePath == "C:\SomeFolder\" acabaria sendo este:

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

E isso também funcionaria sem a barra invertida: ThePath == "C:\SomeFolder" acabaria sendo:

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

Tenha em mente que isso só funciona com os próprios caminhos, e não com a relação entre o caminho e o “disco físico” … então ele não pode dizer se o caminho / arquivo existe ou algo assim, mas com certeza posso dizer se o caminho é uma pasta ou um arquivo …

Se você quiser encontrar diretórios, incluindo aqueles que estão marcados como “ocultos” e “sistema”, tente isto (requer .NET V4):

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

Depois de combinar as sugestões das outras respostas, percebi que tinha a mesma resposta de Ronnie Overby . Aqui estão alguns testes para apontar algumas coisas para pensar:

  1. pastas podem ter “extensões”: C:\Temp\folder_with.dot
  2. arquivos não podem terminar com um separador de diretório (barra)
  3. Existem tecnicamente dois separadores de diretório que são específicos da plataforma – isto é, podem ou não ser barras ( Path.DirectorySeparatorChar e Path.AltDirectorySeparatorChar ).

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

Resultados

 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étodo

 ///  /// Whether the  is a folder (existing or not); /// optionally assume that if it doesn't "look like" a file then it's a directory. ///  /// Path to check /// If the  doesn't exist, does it at least look like a directory name? As in, it doesn't look like a file. /// True if a folder/directory, false if not. 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; } 

Eu uso o seguinte, ele também testa a extensão, o que significa que ela pode ser usada para testar se o caminho fornecido é um arquivo, mas um arquivo que não existe.

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

Eu precisava disso, as postagens ajudaram, isso reduz a uma linha, e se o caminho não é um caminho, ele simplesmente retorna e sai do método. Ele aborda todas as preocupações acima, também não precisa da barra final.

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

Usando a resposta selecionada neste post, examinei os comentários e dei crédito a @ ŞafakGür, @Anthony e @Quinn Wilson por seus bits de informação que me conduziram a essa resposta aprimorada que escrevi e testei:

  ///  /// Returns true if the path is a dir, false if it's a file and null if it's neither or doesn't exist. ///  ///  ///  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; } 

Talvez para UWP C #

 public static async Task 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; } 

Isso não funcionaria?

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

Isso está usando DirectoryInfo para obter o atributo

 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 

Isso funcionará se você tentar passar pelo DirectoryInfo tentando criar um TreeView ou ler um TreeView