2013-02-07 37 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。 「是起訴不對...