如何确定路径是否完全合格?

How to determine if a path is fully qualified?

给定一个路径,我需要知道它是否是完全限定路径(绝对路径)。

我知道有一个名为 System.IO.Path.IsPathRooted 的方法,但是这个 returns 对于像这样的路径是正确的:

我看到了一个名为 IsPathFullyQualified 的方法,我很感兴趣,请参阅 here,但不幸的是,它似乎无法在 .NET Framework 4.5 下被识别。那么 .NET 4.5 是否有任何等效方法?

Full disclaimer: I did not write this code myself and do not own any rights to it. This is based on the .NET Core Source by Microsoft. More info below.

TL;DR: 对于 Windows 系统,您可以将以下 class 添加到您的项目中,然后调用 PathEx.IsPathFullyQualified() 来检查路径是否完全合格:

Public Class PathEx
    Public Shared Function IsPathFullyQualified(path As String) As Boolean
        If path Is Nothing Then
            Throw New ArgumentNullException(NameOf(path))
        End If

        Return Not IsPartiallyQualified(path)
    End Function

    Friend Shared Function IsPartiallyQualified(path As String) As Boolean
        If path.Length < 2 Then
            ' It isn't fixed, it must be relative.  There is no way to specify a fixed
            ' path with one character (or less).
            Return True
        End If

        If IsDirectorySeparator(path.Chars(0)) Then
            ' There is no valid way to specify a relative path with two initial slashes or
            ' \? as ? isn't valid for drive relative paths and \??\ is equivalent to \?\
            Return Not (path.Chars(1) = "?"c OrElse IsDirectorySeparator(path.Chars(1)))
        End If

        ' The only way to specify a fixed path that doesn't begin with two slashes
        ' is the drive, colon, slash format- i.e. C:\
        Return Not ((path.Length >= 3) AndAlso
                    (path.Chars(1) = IO.Path.VolumeSeparatorChar) AndAlso
                    IsDirectorySeparator(path.Chars(2)) AndAlso
                    IsValidDriveChar(path.Chars(0)))
        '           ^^^^^^^^^^^^^^^^
        ' To match old behavior we'll check the drive character for validity as
        ' the path is technically not qualified if you don't have a valid drive.
        ' "=:\" is the "=" file's default data stream.
    End Function

    Friend Shared Function IsDirectorySeparator(c As Char) As Boolean
        Return c = Path.DirectorySeparatorChar OrElse c = Path.AltDirectorySeparatorChar
    End Function

    Friend Shared Function IsValidDriveChar(value As Char) As Boolean
        Return (value >= "A"c AndAlso value <= "Z"c) OrElse
               (value >= "a"c AndAlso value <= "z"c)
    End Function
End Class

这段代码(和注释)来自哪里?

这是从公开可用的 .NET Core Source Browser 中提取的,适用于 .NET Framework,并转换为 VB.NET。

.NET Core 的 IsPathFullyQualified() method uses an internal method called IsPartiallyQualified() to check if the path is fully qualified (not partially qualified). That internal method has different logic for different Operating Systems. This 是上述代码所基于的 Windows 版本。

用法:

Console.WriteLine(PathEx.IsPathFullyQualified("C:Documents"))    ' False
Console.WriteLine(PathEx.IsPathFullyQualified("/Documents"))     ' False
Console.WriteLine(PathEx.IsPathFullyQualified("C:\Documents"))   ' True

这是确定路径是否完全合格且有效的另一种可能方法。
此方法(*) 尝试在解析新 Uri 时使用 Uri.TryCreate(). When this method succeeds, it then inspects the non-public IsDosPath Property, which is set internally by the Uri class 从提供的路径生成 Uri 以确定它是否有效以及类型它代表的资源。

您可以在 .Net Source code 中看到,PrivateParseMinimal() 方法执行大量测试以验证路径,并检查 DosPath 是否已 root。

Imports System.Reflection

Private Function PathIsFullyQualified(path As String) As (Valid As Boolean, Parsed As String)
    Dim flags = BindingFlags.GetProperty Or BindingFlags.Instance Or BindingFlags.NonPublic
    Dim uri As Uri = Nothing
    If Uri.TryCreate(path, UriKind.Absolute, uri) Then
        Dim isDosPath = CBool(uri.GetType().GetProperty("IsDosPath", flags).GetValue(uri))
        Return (isDosPath, uri.LocalPath)
    End If
    Return (False, String.Empty)
End Function

* 此方法 return 是 Named Tuple:从 Visual Basic 2017 开始支持

我测试了以下路径;他们都是 return False 当我假设他们应该时,除了 "file://c:/Documents":,但是 PathIsFullyQualified 方法也 returns 相应的本地路径,c:\Documents:

Dim isOk1 = PathIsFullyQualified("C:Documents")            'False
Dim isOk2 = PathIsFullyQualified("/Documents")             'False
Dim isOk3 = PathIsFullyQualified("file://c:/Documents")    'True  => isOk3.Parsed = "c:\Documents"
Dim isOk4 = PathIsFullyQualified("\Documents")            'False
Dim isOk5 = PathIsFullyQualified("..\Documents")           'False
Dim isOk6 = PathIsFullyQualified(".\Documents")            'False
Dim isOk7 = PathIsFullyQualified("\Documents")             'False
Dim isOk8 = PathIsFullyQualified("//Documents")            'False
Dim isOk9 = PathIsFullyQualified(".Documents")             'False
Dim isOkA = PathIsFullyQualified("..Documents")            'False
Dim isOkB = PathIsFullyQualified("http://C:/Documents")    'False
Dim isOkC = PathIsFullyQualified("Cd:\Documents")          'False
Dim isOkD = PathIsFullyQualified("1:\Documents")           'False
Dim isOkE = PathIsFullyQualified("Z:\Another Path//docs") 'True => isOkE.Parsed = "Z:\Another Path\docs"
Dim isOkF = PathIsFullyQualified(":\Another Path//docs")  'False

我偶然发现了这个,想使用这种方法,但意识到其他答案过于复杂。

我在这里查看了 MS 的源代码:https://source.dot.net/#System.Private.CoreLib/Path.cs,3b4bff90471c3a68

这里: https://referencesource.microsoft.com/#mscorlib/system/io/path.cs,807960f08fca497d

我注意到的是,在第二个 link 中,检查 IsPathRooted 的方法之一是检查此:(length >= 2 && path[1] == VolumeSeparatorChar)。我只是将该检查修改为充实的方法。

.Net 源代码 (link 1) 本质上是 IsPathFullyQualified => !IsPathRooted,我认为这还不足以进行健全性检查。所以这是我的替代品。

public static bool IsPathFullyQualified(string path)
{
    if (path == null)
        throw new ArgumentNullException(nameof(path));
    return path.Length >= 3 && path[1] == System.IO.Path.VolumeSeparatorChar && ( path[2] == System.IO.Path.DirectorySeparatorChar | path[2] == System.IO.Path.AltDirectorySeparatorChar );
}

编辑:我意识到上面这个简短的方法不接受 UNC 路径。因此,更新版本(无可否认,这只是通过消除 IsPartiallyQualified 方法而简化的原始答案版本)如下:

public static bool IsPathFullyQualified(string path)
        {
            if (path == null) throw new ArgumentNullException(nameof(path));
            if (path.Length < 2) return false; //There is no way to specify a fixed path with one character (or less).
            if (path.Length == 2 && IsValidDriveChar(path[0]) && path[1] == System.IO.Path.VolumeSeparatorChar) return true; //Drive Root C:
            if (path.Length >= 3 && IsValidDriveChar(path[0]) &&  path[1] == System.IO.Path.VolumeSeparatorChar && IsDirectorySeperator(path[2])) return true; //Check for standard paths. C:\
            if (path.Length >= 3 && IsDirectorySeperator(path[0]) && IsDirectorySeperator(path[1])) return true; //This is start of a UNC path
            return false; //Default
        }

        private static bool IsDirectorySeperator(char c) => c == System.IO.Path.DirectorySeparatorChar | c == System.IO.Path.AltDirectorySeparatorChar;
        private static bool IsValidDriveChar(char c) => c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';