这种使相对路径有效的方法吗?

时间:2011-06-05 13:38:03

标签: c# .net path uri relative-path

由于.NET不包含用于创建相对路径的API,因此我使用了Uri的MakeRelativeUri方法。这样可行,但我遇到过几种情况,因为Uri没有被转义。所以我也补了一下:

public static string MakeRelativePath(string basePath, string tgtPath) {
    return
        Uri.UnescapeDataString(
            new Uri(basePath, UriKind.Absolute)
                .MakeRelativeUri(new Uri(tgtPath, UriKind.Absolute))
            .ToString()
        ).Replace('/', Path.DirectorySeparatorChar);
}

这个版本的似乎可以工作,但是让我感到有些疑问:这个无偿的unescaping可能会破坏任何有效的本地文件系统路径吗?

相关: How to get relative path from absolute path 这个问题的答案并没有解决不寻常的角色和逃避的问题,因此不回答这个问题。

1 个答案:

答案 0 :(得分:4)

您可以使用System.UriPathDifference方法使用的基础算法,而不是转义,取消转换和替换。在这里,它通过Reflector恢复并进行了修改,以获得更好的可读性。它也被修改为对DOS样式路径使用反斜杠而不是URI的正斜杠,并且比较总是不区分大小写。

static string PathDifference(string path1, string path2)
{
    int c = 0;  //index up to which the paths are the same
    int d = -1; //index of trailing slash for the portion where the paths are the same

    while (c < path1.Length && c < path2.Length)
    {
        if (char.ToLowerInvariant(path1[c]) != char.ToLowerInvariant(path2[c]))
        {
            break;
        }

        if (path1[c] == '\\')
        {
            d = c;
        }

        c++;
    }

    if (c == 0)
    {
        return path2;
    }

    if (c == path1.Length && c == path2.Length)
    {
        return string.Empty;
    }


    System.Text.StringBuilder builder = new System.Text.StringBuilder();

    while (c < path1.Length)
    {
        if (path1[c] == '\\')
        {
            builder.Append(@"..\");
        }
        c++;
    }

    if (builder.Length == 0 && path2.Length - 1 == d)
    {
        return @".\";
    }

    return builder.ToString() + path2.Substring(d + 1);
}

输入的期望似乎是,如果任一路径表示目录,则它必须具有尾部反斜杠。显然,路径也必须是非空的。

以下是一些示例输入和输出......看看它是否符合您的需求。

Path1                   Path2               Output
C:\test\path1\path2\    C:\test\            ..\..\
C:\test\path1\file      C:\test\            ..\
C:\test\path1\path2\    C:\                 ..\..\..\
C:\test\path1\path2\    D:\                 D:\
C:\test\path1\path2\    C:\test\path1\pathA ..\pathA
C:\test\                C:\test\    
C:\test\                C:\test\file        file
C:\test\file            C:\test\            .\
C:\test\path #1!\path2\ C:\test\            ..\..\