C# 从相对URI计算本地路径的正确方法

C# 从相对URI计算本地路径的正确方法,c#,vb.net,winforms,uri,C#,Vb.net,Winforms,Uri,似乎没有标准的方法来计算相对值(此属性仅对绝对URI有效),例如与文件掩码(*.ext)结合使用。问题是生成类似于my%20folder/的内容,而不是my folder\ 以下是我发现的一个解决方法: 模块1 副标题() Dim path1为String=“C:\my folder\” Dim path2为String=“C:\” MsgBox(GetPathDiff(path1,path2))输出“我的文件夹”(不带引号) 端接头 私有函数GetPathDiff(路径1作为字符串,路径2作为

似乎没有标准的方法来计算相对值(
此属性仅对绝对URI有效
),例如与文件掩码(*.ext)结合使用。问题是生成类似于
my%20folder/
的内容,而不是
my folder\

以下是我发现的一个解决方法:

模块1
副标题()
Dim path1为String=“C:\my folder\”
Dim path2为String=“C:\”
MsgBox(GetPathDiff(path1,path2))输出“我的文件夹”(不带引号)
端接头
私有函数GetPathDiff(路径1作为字符串,路径2作为字符串)作为字符串
Dim uri1作为新Uri(路径1)
Dim uri2作为新Uri(路径2)
Dim uri3作为Uri=uri2.MakeRelativeUri(uri1)
返回Uri.UnescapeDataString(uri3.OriginalString)。替换(“/”,“\”)
端函数
端模块
我发现这是一种相当笨拙的方法,可能有一些隐藏的石头我还没有偶然发现,即这种方法对于不同的用例不是100%稳定的

有更好的方法吗?[editedit] 好吧,经过一点思考,我确实想出了一个替代方案,但可能不是所有人都喜欢:

void Main()
{
    var path1 = @"C:\Program Files\Internet Explorer\";
    var path2 = @"C:\temp\";
    var sb = new StringBuilder(1000);
    PathRelativePathTo(sb, path1, 0, path2, 0);
    sb.ToString().Dump();
}

/*
BOOL PathRelativePathTo(
  _Out_  LPTSTR pszPath,
  _In_   LPCTSTR pszFrom,
  _In_   DWORD dwAttrFrom,
  _In_   LPCTSTR pszTo,
  _In_   DWORD dwAttrTo
);
*/
[DllImport("Shlwapi.dll")]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool PathRelativePathTo(
    [Out] StringBuilder result,
    [In] string pathFrom,
    [In] int dwAttrFrom,
    [In] string pathTo,
    [In] int dwAttrTo);
哦,我有个主意-这能满足你(或多或少)的需要吗

public string PathDiff(string path1, string path2)
{
    var replace1 = path1.Replace(path2, string.Empty);
    var replace2 = path2.Replace(path1, string.Empty);
    return Path.IsPathRooted(replace1) ? replace2 : replace1;
}
或者更好:

public string PathDiff(string path1, string path2)
{
    return path1.Length > path2.Length ? 
        path1.Replace(path2, string.Empty) : 
        path2.Replace(path1, string.Empty);
}
(编辑:derp,点击submit太早):

不幸的是,没有内置的相对路径帮助程序,但基本上是通过现有的工具实现的,如下所示:

var path1 = @"C:\dev\src\release\Frontend\";
var path2 = @"C:\dev\src\";

var path1Uri = new Uri(path1);
var path2Uri = new Uri(path2);

var from1to2 = path1Uri.MakeRelativeUri(path2Uri).OriginalString;
var from2to1 = path2Uri.MakeRelativeUri(path1Uri).OriginalString;

Console.WriteLine("To go from {0} to {1}, you need to {2}", path1, path2, from1to2);
Console.WriteLine("To go from {0} to {1}, you need to {2}", path2, path1, from2to1);
输出:

To go from C:\dev\src\release\Frontend\ to C:\dev\src\, you need to ../../
To go from C:\dev\src\ to C:\dev\src\release\Frontend\, you need to release/Frontend/
C:\dev\src\
C:\dev\src\release\Frontend\
现在,对于斜杠差异“\”vs“/”,如果您将最终结果包装在
Path.GetFullPath
中,它将自动解决这些差异:

Console.WriteLine(Path.GetFullPath(Path.Combine(path1, from1to2)));
Console.WriteLine(Path.GetFullPath(Path.Combine(path2, from2to1)));
输出:

To go from C:\dev\src\release\Frontend\ to C:\dev\src\, you need to ../../
To go from C:\dev\src\ to C:\dev\src\release\Frontend\, you need to release/Frontend/
C:\dev\src\
C:\dev\src\release\Frontend\
(注:与其说是一个答案,不如说是一个感叹,但我希望其中的一些内容是有益的。)

如果您试图在这里获得两个文件系统路径之间的相对路径,那么最好还是坚持使用文件系统API

起初,我的问题看起来与你的目标相同,在我对这一段进行编辑之前,我建议先看一下。但仔细观察,我在写这篇文章时发现解决方案并不是很好

我对
Uri
的担心是,它是围绕Uri路径的规则设计的,这些规则不一定与文件系统路径的规则相同。例如,URI规范说,“.”的路径段是“打算在相对路径引用的开始处使用”,而对于文件系统路径来说,在路径中间有一个完全合法的(如果有点奇怪)。例如,
c:\.\a\.\b\.\c
是合法的,其含义与
c:\a\b\c
相同

众所周知,文件系统规范化很容易出错,因此可能存在比这更微妙的问题


因此,从理论上讲,一个特定于文件系统的API要比使用设计用于处理URI的代码更好,因为它希望产生在文件系统上工作的结果。实际上,.NET似乎没有提供用于计算相对路径的文件系统感知API,令人惊讶的是,用于此目的的Win32 API,
PathRelativePathTo
,得到了“问题错误…”关于转义,例如
%20
之类的东西呢?另外,我需要停留在相对路径级别,因此无法执行
GetFullPath
。它被用作
winrar
进程的参数,否则会导致目录结构错误。@Neolisk啊,如果您需要相对路径格式,我不确定是否有
Uri.UnescapeDataString
的替代品……我会仔细考虑一下,但您可能已经有了“最佳”的解决方案。我认为您的PathDiff只能处理一条路径是另一条路径的子路径的情况。不管路径是如何嵌套的,URI方法都可以工作。考虑这个例子:“我的文件夹\ 123 \ 7876“减去”C:\测试\ 879 \ 123“应该等于这个….. \我的文件夹\ 123 \ 7876”,另一个例子是“C:\我的文件夹“减去”X:\“这导致”C:\我的文件夹\“,意思是<代码> MaKelelTurviuri < /代码>尽力解决一个相对路径,但只有绝对路径工作在这种情况下,它很好地解决了这个问题。是的,很遗憾它没有“嵌入”到IO名称空间中,但我认为您所拥有的可能是适合您的场景的最佳解决方案…我想到了任何东西,我会在这里编辑,但不抱希望…您为什么在这里使用Uri?从您的代码来看,您似乎正在尝试处理文件路径。这并不是Uri真正关注的焦点——它支持这一点的唯一原因是因为file:Uri。它给出的值是正确的-如果您在调试器中查看这里的uri1和uri2,您将看到它们是正确的file:///C:/my%20folder/ 及file:///C:/ 因此,正确的相对URI实际上是我的%20文件夹。您可能正在寻找相对的文件系统路径?在URI的世界里,这并不是一个真正的概念,所以它会很笨拙。@IanGriffiths:我在网上的某个地方找到了一个使用URI进行路径区分的实现,这似乎是一个相当干净的实现,直到现在。我仍然认为,就代码行度量而言,它比其他解决方案要好。