.NET Framework是否有將路徑(例如"C:\whatever.txt"
)轉換爲文件URI(例如"file:///C:/whatever.txt"
)的方法?將文件路徑轉換爲文件URI?
System.Uri類有相反的結果(從文件URI到絕對路徑),但沒有什麼可以找到轉換爲文件URI。
此外,這是而不是一個ASP.NET應用程序。
.NET Framework是否有將路徑(例如"C:\whatever.txt"
)轉換爲文件URI(例如"file:///C:/whatever.txt"
)的方法?將文件路徑轉換爲文件URI?
System.Uri類有相反的結果(從文件URI到絕對路徑),但沒有什麼可以找到轉換爲文件URI。
此外,這是而不是一個ASP.NET應用程序。
構造函數System.Uri
能夠解析完整文件路徑並將它們轉換爲URI樣式路徑。所以,你可以做到以下幾點:
var uri = new System.Uri("c:\\foo");
var converted = uri.AbsoluteUri;
VB.NET:
Dim URI As New Uri("D:\Development\~AppFolder\Att\1.gif")
不同的輸出:
URI.AbsolutePath -> D:/Development/~AppFolder/Att/1.gif
URI.AbsoluteUri -> file:///D:/Development/~AppFolder/Att/1.gif
URI.OriginalString -> D:\Development\~AppFolder\Att\1.gif
URI.ToString -> file:///D:/Development/~AppFolder/Att/1.gif
URI.LocalPath -> D:\Development\~AppFolder\Att\1.gif
一個內膽:
New Uri("D:\Development\~AppFolder\Att\1.gif").AbsoluteUri
輸出:
file:///D:/Development/~AppFolder/Att/1.gif
至少在.NET 4.5 +你也可以這樣做:
var uri = new System.Uri("C:\\foo", UriKind.Absolute);
有一天你不會冒險得到'UriFormatException'嗎? – berezovskyi 2015-12-03 07:33:12
這也不能正常工作,'新Uri(@「C:\%51.txt」,UriKind.Absolute).AbsoluteUri'返回 '「file:/// C:/Q.txt」'而不是' 「file:/// C:/%2551.txt」 – poizan42 2016-03-01 20:58:58
沒有什麼人似乎意識到的是,沒有一個System.Uri
構造的正確處理與%確定路徑在他們的標誌。
new Uri(@"C:\%51.txt").AbsoluteUri;
這給你"file:///C:/Q.txt"
,而不是"file:///C:/%2551.txt"
。
這兩個不推薦的dontEscape參數的值都沒有什麼區別,並且指定UriKind也給出了相同的結果。試用UriBuilder也沒有幫助:
new UriBuilder() { Scheme = Uri.UriSchemeFile, Host = "", Path = @"C:\%51.txt" }.Uri.AbsoluteUri
這也返回"file:///C:/Q.txt"
。
據我所知,框架實際上沒有任何正確的做法。
我們可以用斜槓代替反斜槓嘗試把它和飼料的路徑Uri.EscapeUriString
- 即
new Uri(Uri.EscapeUriString(filePath.Replace(Path.DirectorySeparatorChar, '/'))).AbsoluteUri
這似乎在第一個工作,但如果你給它的路徑C:\a b.txt
那麼你最終與file:///C:/a%2520b.txt
,而不是file:///C:/a%20b.txt
- 不知何故,它決定一些序列應解碼,但不是其他人。現在我們只能自己加上"file:///"
的前綴,但是這並沒有考慮到像\\remote\share\foo.txt
這樣的UNC路徑 - 在Windows上似乎普遍接受的是將它們變成file://remote/share/foo.txt
形式的僞url,所以我們應該考慮到這一點好。
EscapeUriString
也有,它並沒有逃脫'#'
字符的問題。現在看來,我們別無選擇,只能從頭開始制定我們自己的方法。所以這是我的建議:
public static string FilePathToFileUrl(string filePath)
{
StringBuilder uri = new StringBuilder();
foreach (char v in filePath)
{
if ((v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z') || (v >= '0' && v <= '9') ||
v == '+' || v == '/' || v == ':' || v == '.' || v == '-' || v == '_' || v == '~' ||
v > '\xFF')
{
uri.Append(v);
}
else if (v == Path.DirectorySeparatorChar || v == Path.AltDirectorySeparatorChar)
{
uri.Append('/');
}
else
{
uri.Append(String.Format("%{0:X2}", (int)v));
}
}
if (uri.Length >= 2 && uri[0] == '/' && uri[1] == '/') // UNC path
uri.Insert(0, "file:");
else
uri.Insert(0, "file:///");
return uri.ToString();
}
這種故意留下+和:未編碼的,這似乎是多麼它通常是在Windows上進行。它也僅對latin1進行編碼,因爲Internet Explorer無法理解文件URL中的unicode字符(如果它們已編碼)。
的解決方案上面的不工作在Linux上。
使用.NET的核心,試圖在一個例外執行new Uri("/home/foo/README.md")
結果:
Unhandled Exception: System.UriFormatException: Invalid URI: The format of the URI could not be determined.
at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
at System.Uri..ctor(String uriString)
...
你需要給CLR你有什麼樣的URL的一些提示。
這工作:
Uri fileUri = new Uri(new Uri("file://"), "home/foo/README.md");
...和fileUri.ToString()
返回的字符串是"file:///home/foo/README.md"
這適用於Windows,太。
new Uri(new Uri("file://"), @"C:\Users\foo\README.md").ToString()
...發出"file:///C:/Users/foo/README.md"
UrlCreateFromPath來救援!好了,不完全的,因爲它不支持擴展和UNC路徑格式,但事實並非如此難以克服:
public static Uri FileUrlFromPath(string path)
{
const string prefix = @"\\";
const string extended = @"\\?\";
const string extendedUnc = @"\\?\UNC\";
const string device = @"\\.\";
const StringComparison comp = StringComparison.Ordinal;
if(path.StartsWith(extendedUnc, comp))
{
path = prefix+path.Substring(extendedUnc.Length);
}else if(path.StartsWith(extended, comp))
{
path = prefix+path.Substring(extended.Length);
}else if(path.StartsWith(device, comp))
{
path = prefix+path.Substring(device.Length);
}
int len = 1;
var buffer = new StringBuilder(len);
int result = UrlCreateFromPath(path, buffer, ref len, 0);
if(len == 1) Marshal.ThrowExceptionForHR(result);
buffer.EnsureCapacity(len);
result = UrlCreateFromPath(path, buffer, ref len, 0);
if(result == 1) throw new ArgumentException("Argument is not a valid path.", "path");
Marshal.ThrowExceptionForHR(result);
return new Uri(buffer.ToString());
}
[DllImport("shlwapi.dll", CharSet=CharSet.Auto, SetLastError=true)]
static extern int UrlCreateFromPath(string path, StringBuilder url, ref int urlLength, int reserved);
如果路徑以一個特殊的前綴開頭,它就會被刪除。儘管文檔沒有提到它,但是即使緩衝區較小,該函數也會輸出URL的長度,所以我首先獲取長度,然後分配緩衝區。
一些非常有趣的觀察我的是,雖然「\\設備\路徑」是否正確轉化爲「文件://設備/路徑」,特別是「\\本地主機\路徑」轉化爲只是「文件:///路徑」。
WinApi函數設法對特殊字符進行編碼,但留下Unicode編碼的特殊字符,不像Uri construtor。在這種情況下,絕對URI包含正確編碼的URL,而OriginalString可以用來保留Unicode字符。
這打印文件:/// C:/富嗎? – knocte 2012-10-21 02:31:19
我的意思是,如果「轉換」打印...... – knocte 2012-10-21 12:29:56
'變種路徑=新URI(「文件:/// C:/whatever.txt」).LocalPath;'導通一個URI返回到一個本地文件路徑過於爲任何人這需要這個。 – Pondidum 2012-11-08 16:06:40