【问题标题】:Will this method of making relative paths work?这种制作相对路径的方法会起作用吗?
【发布时间】:2011-09-08 18:04:40
【问题描述】:

由于 .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);
}

这个版本似乎可以工作,但它让我感到有些疑惑:难道没有任何有效的本地文件系统路径可能会破坏这种无偿的转义吗?

相关: How to get relative path from absolute path 该问题的答案根本没有解决异常字符和转义的问题,因此不回答这个问题。

【问题讨论】:

  • @Eamon 这里有一些很好的答案:stackoverflow.com/questions/275689/… 如果是我,我会选择 P/Invokes to PathRelativePathTo()的解决方案
  • 是的,我看到一个也在使用 Uri 的答案,但没有转义,即 borked。 P/调用;嗯,这很慢并且依赖于平台,这意味着您可能会遇到 x86/x64 问题、非完全信任问题,当然,silverlight/XNA 之类的东西不一定支持它。它会起作用,但这不是我的第一选择。
  • @Eamon 我可以看到。我我以 Windows 为中心,所以 P/Invoking 很好。我认为速度不是问题——你不会在应用程序的热循环中调用它吧?!!
  • PathRelativePathTo 据我所知没有触及文件系统。它纯粹基于文本。如果你想知道它是如何实现的,你可以随时查看 Wine 源代码!

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


【解决方案1】:

您可以只使用System.UriPathDifference 方法使用的底层算法,而不是转义、取消转义和替换。在这里,通过反射器恢复并进行了修改以获得更好的可读性。它还被修改为对 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\            ..\..\

【讨论】:

  • 是的,尾随的反斜杠是相当固有的,如果您考虑一下 - 算法实际上无法访问文件系统,对吧?
  • 我不太愿意通过反射器来解决这个问题 - 我不是版权律师,谁知道怎么办......
  • 顺便说一句,感谢您的努力,这当然是一种有趣的方法!
  • ...它表明Uri 没有进行任何类型的标准化,这在这里有点不幸;例如比较 C:\test\path1\path2` to C:\test\\path1\pathA` 并没有做它应该做的事情。另一方面,C:\test\xy\..\path1\pathA 确实可以与上面的MakeRelativeUri 一起使用,但这里不适用……
猜你喜欢
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 2017-07-12
  • 2011-03-30
  • 2013-02-19
  • 2015-08-30
  • 2011-03-17
  • 2014-06-25
相关资源
最近更新 更多