关于c#:检查路径是文件还是目录的更好方法?

Better way to check if a Path is a File or a Directory?

我正在处理目录和文件的TreeView。用户可以选择文件或目录,然后对其进行操作。这要求我有一个根据用户选择执行不同操作的方法。

目前我正在做类似的事情来确定路径是文件还是目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bool bIsFile = false;
bool bIsDirectory = false;

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

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

我禁不住觉得有更好的方法可以做到这一点!我希望找到一个标准的.NET方法来处理这个问题,但我一直没能做到。是否存在这样的方法,如果不存在,确定路径是文件还是目录最直接的方法是什么?


从如何判断路径是文件还是目录:

1
2
3
4
5
6
7
8
// 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");

.NET 4.0的更新+

根据下面的注释,如果您在.NET 4.0或更高版本上(并且最大性能不是关键),则可以更清晰地编写代码:

1
2
3
4
5
6
7
// 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");


用这些怎么样?

1
2
File.Exists();
Directory.Exists();


如果路径是目录或文件,则仅使用此行即可获得:

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


这是我的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    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));
    }

这与其他人的答案相似,但并不完全相同。


作为directory.exists()的替代方法,您可以使用file.get attributes()方法获取文件或目录的属性,这样您就可以创建这样的助手方法:

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

在填充包含该项附加元数据的控件时,还可以考虑将对象添加到TreeView控件的标记属性中。例如,您可以为文件添加一个fileinfo对象,为目录添加一个directoryinfo对象,然后在标记属性中测试项类型以保存在单击项时进行额外的系统调用以获取该数据。


考虑到exists和attributes属性的行为,这是我能想到的最好的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
    }
}

测试方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    [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
otepad.exe"
;

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

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

最准确的方法是使用shlwapi.dll中的一些互操作代码

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

你可以这样称呼它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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);
}


在综合了其他答案的建议之后,我意识到我得出的答案与罗尼·奥弗里的答案大致相同。下面是一些测试,指出一些需要考虑的问题:

  • 文件夹可以有"扩展名":C:\Temp\folder_with.dot
  • 文件不能以目录分隔符(斜杠)结尾
  • 从技术上讲,有两个特定于平台的目录分隔符,即可以斜杠,也可以不斜杠(Path.DirectorySeparatorCharPath.AltDirectorySeparatorChar)
  • 测试(LIQPAD)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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
    otadir.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
    on_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);
    }

    结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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
    otadir.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
    on_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

    方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    /// <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;
    }


    当遇到类似的问题时,我遇到了这个问题,但我需要检查路径是否是文件或文件夹的路径,而该文件或文件夹可能并不实际存在。上面提到的答案有一些评论,它们不适用于这种情况。我找到了一个适合我的解决方案(我使用vb.net,但如果需要可以转换):

    1
    2
    3
    4
    5
    6
    7
    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

    希望这对某人有帮助!


    我很快就知道了,但我想我还是会分享这个。如果只将路径作为字符串来处理,那么很容易将其理解为饼图:

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

    例如:ThePath =="C:\SomeFolder\File1.txt"最终将是:

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

    另一个例子:ThePath =="C:\SomeFolder\"最终将是:

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

    如果没有后面的反斜杠,这也可以工作:ThePath =="C:\SomeFolder"最终将是:

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

    请记住,这只适用于路径本身,而不是路径与"物理磁盘"之间的关系…所以它不能告诉你路径/文件是存在的还是类似的,但是它可以告诉你路径是文件夹还是文件…


    我们使用的是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    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;
        }

      }

    }

    如果要查找目录,包括标记为"hidden"和"system"的目录,请尝试此操作(需要.NET v4):

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

    我明白了,我迟到10年了。我正面临这样的情况:从某个属性,我可以接收文件名或完整的文件路径。如果没有提供路径,我必须通过附加由另一个属性提供的"全局"目录路径来检查文件是否存在。

    以我为例

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

    做了这个把戏。好吧,这不是魔法,但也许这能让人省下几分钟的时间来搞清楚。因为这只是一个字符串解析,所以带点的dir名称可能会给出误报…


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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));
              }
         }
    }


    我使用下面的代码,它还测试扩展名,这意味着如果提供的路径是一个文件,但文件不存在,它可以用于测试。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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;
    }


    我需要这个,贴子帮助,这可以把它简化为一行,如果路径根本不是路径,它只返回并退出方法。它解决了上述所有问题,也不需要尾随斜杠。

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

    我用这篇文章中选定的答案,看了评论并相信@?Afakg_r,@Anthony和@Quinn Wilson提供了他们的信息位,这些信息位使我得到了这个改进的答案,我写了这篇文章并进行了测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
        /// <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;
        }


    可能是UWP C#

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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;
        }

    这不管用吗?

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


    这是使用directoryinfo获取属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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

    如果您试图通过directoryInfo尝试创建TreeView或读取TreeView,这将有效。