2013-02-07 34 views
2

似乎没有标准的方法来计算LocalPath从相对的URIthis property is valid only for absolute URIs),与Path.Combine结合使用,例如将其与文件掩码(* .EXT)。问题是MakeRelativeUri产生的东西类似于my%20folder/,而不是my folder\从相对URI计算本地路径的正确方法

这里是一个解决办法,我发现:

Module Module1 
    Sub Main() 
    Dim path1 As String = "C:\my folder\" 
    Dim path2 As String = "C:\" 
    MsgBox(GetPathDiff(path1, path2)) 'outputs "my folder\" (without quotes) 
    End Sub 

    Private Function GetPathDiff(path1 As String, path2 As String) As String 
    Dim uri1 As New Uri(path1) 
    Dim uri2 As New Uri(path2) 
    Dim uri3 As Uri = uri2.MakeRelativeUri(uri1) 
    Return Uri.UnescapeDataString(uri3.OriginalString).Replace("/", "\") 
    End Function 
End Module 

我觉得这是一个相当笨拙的方式,并可能有一些隐藏的宝石我还不偶然发现的,即这种方法是不100%稳定不同的用例。

有没有更好的方法来做到这一点?

+0

你为什么在这里使用Uri?从你的代码看起来你正在试图处理文件路径。这不是Uri的焦点 - 它有任何支持的唯一原因是file:URI。它给你的价值是正确的 - 如果你在调试器中查看uri1和uri2,你会看到它们是file:/// C:/ my%20folder /和file:/// C:/所以正确相对URI确实是我的%20folder。想必你正在寻找一个相对的文件系统路径?这在Uris的世界里并不是一个真正的概念,所以它会变得笨拙。 –

+0

@Igriffiths:我发现一个实现在网络上的某处使用URI来完成路径差异,直到现在,这似乎是一个相当干净的路径。就代码行数而言,我仍然认为它比其他解决方案更好。 – Neolisk

回答

1

[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,点击提交太快):

有没有内置的相对路径的助手,很遗憾,但你已经基本上得到了它与你已经有了,像这样:

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/ 

,作为斜线差异 “\” 与 “/”,如果你包裹在Path.GetFullPath最终结果,它会自动解决分歧:

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

输出:

C:\dev\src\ 
C:\dev\src\release\Frontend\ 
+0

转义如何,即'%20'之类的东西?另外,我需要停留在相对路径级别,所以我不能执行'GetFullPath'。它被用作'winrar'进程的参数,否则会导致目录结构错误。 – Neolisk

+0

@Neilisk啊,如果你需要相对路径格式,我不确定是否有'Uri.UnescapeDataString'的替代方案...我会思考一下,但是你可能已经有了“最好”的解决方案。 – JerKimball

+0

我认为你的PathDiff只能处理一个路径是另一个路径的情况。无论路径如何嵌套,URI方法都可以工作。考虑这个例子:“C:\ my folder \ 123 \ 7876”减去“C:\ test \ 879 \ 123”应该等于这个“.. \ .. \ my folder \ 123 \ 7876”。 – Neolisk

2

(注:与其说是答案哀叹,但我希望一些这方面的信息。)

如果你想在这里做的是得到一个相对两个文件系统路径之间的路径,那么你最好坚持使用filesytem API。

最初在Calculating the path relative to some root- the inverse of Path.Combine的问题看起来与您的目标是一样的,在我将编辑应用于本段之前,我建议看看它。但仔细观察后发现,我写这篇文章时的解决方案并不是那么好。

我在Uri这里担心的是它是围绕URI路径的规则设计的,这些规则不一定与文件系统路径相同。例如,URI规范说道路段为“。“是”旨在用于相对路径引用的开始处“,而对于文件系统路径,将它们放在路径中间是完全合法的(如果有点奇怪),例如c:\.\a\.\b\.\c是合法的并且意味着与c:\a\b\c相同。

文件系统的规范化是出了名的容易出错,所以有可能比这更微妙的问题。

所以从理论上讲,一个特定的文件系统的API会比使用代码设计以处理URI的更好希望它能产生可以在文件系统上运行的结果,实际上,.NET似乎没有提供文件系统感知的API来计算相对路径,令人惊讶的是,Win32 API的确切用途是PathRelativePathTo。 “是起诉不对...