Apa yang tampaknya tidak disadari siapa pun adalah bahwa tidak satu pun System.Uri
konstruktor yang menangani dengan benar jalur tertentu dengan tanda persen di dalamnya.
new Uri(@"C:\%51.txt").AbsoluteUri;
Ini memberi Anda "file:///C:/Q.txt"
alih-alih "file:///C:/%2551.txt"
.
Tidak ada nilai dari argumen dontEscape yang ditinggalkan membuat perbedaan, dan menentukan UriKind memberikan hasil yang sama juga. Mencoba dengan UriBuilder juga tidak membantu:
new UriBuilder() { Scheme = Uri.UriSchemeFile, Host = "", Path = @"C:\%51.txt" }.Uri.AbsoluteUri
Ini juga kembali "file:///C:/Q.txt"
.
Sejauh yang saya tahu kerangka sebenarnya tidak memiliki cara untuk melakukan ini dengan benar.
Kita dapat mencobanya dengan mengganti garis miring terbalik dengan garis miring ke depan dan memberi makan jalur ke Uri.EscapeUriString
- yaitu
new Uri(Uri.EscapeUriString(filePath.Replace(Path.DirectorySeparatorChar, '/'))).AbsoluteUri
Ini tampaknya bekerja pada awalnya, tetapi jika Anda memberikan jalan C:\a b.txt
maka Anda berakhir dengan file:///C:/a%2520b.txt
bukannya file:///C:/a%20b.txt
- entah bagaimana itu memutuskan bahwa beberapa urutan harus diterjemahkan tetapi tidak yang lain. Sekarang kita bisa awalan dengan "file:///"
diri kita sendiri, tetapi ini gagal untuk mengambil jalur UNC seperti \\remote\share\foo.txt
memperhitungkan - apa yang tampaknya diterima secara umum pada Windows adalah mengubahnya menjadi uraian semu formulir file://remote/share/foo.txt
, jadi kita juga harus memperhitungkannya.
EscapeUriString
juga memiliki masalah yang tidak luput dari '#'
karakter. Tampaknya pada titik ini kita tidak punya pilihan lain selain membuat metode sendiri dari awal. Jadi ini yang saya sarankan:
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();
}
Ini sengaja menyisakan + dan: tidak ter-enkripsi seperti yang biasanya dilakukan pada Windows. Itu juga hanya mengkodekan latin1 karena Internet Explorer tidak dapat memahami karakter unicode dalam url file jika mereka dikodekan.
var path = new Uri("file:///C:/whatever.txt").LocalPath;
mengubah Uri kembali menjadi filepath lokal juga untuk siapa saja yang membutuhkan ini.