gì không ai dường như nhận ra là không ai trong số các System.Uri
constructors xử lý một cách chính xác đường dẫn nhất định với phần trăm dấu hiệu trong đó.
new Uri(@"C:\%51.txt").AbsoluteUri;
Điều này cung cấp cho bạn "file:///C:/Q.txt"
thay vì "file:///C:/%2551.txt"
.
Không có giá trị nào của đối số dontEscape không được chấp nhận sẽ tạo ra bất kỳ sự khác biệt nào và chỉ định UriKind cũng cho kết quả tương tự. Việc thử với UriBuilder cũng không giúp được:
new UriBuilder() { Scheme = Uri.UriSchemeFile, Host = "", Path = @"C:\%51.txt" }.Uri.AbsoluteUri
Điều này cũng trả về "file:///C:/Q.txt"
.
Theo tôi có thể nói khung thực sự thiếu bất kỳ cách nào để thực hiện điều này một cách chính xác.
Chúng tôi có thể thử nó bằng cách thay thế những dấu xồ nguợc với dấu gạch chéo và thức ăn đường dẫn đến Uri.EscapeUriString
- tức là
new Uri(Uri.EscapeUriString(filePath.Replace(Path.DirectorySeparatorChar, '/'))).AbsoluteUri
Điều này dường như làm việc lúc đầu, nhưng nếu bạn cho nó con đường C:\a b.txt
sau đó bạn kết thúc với file:///C:/a%2520b.txt
thay vì file:///C:/a%20b.txt
- bằng cách nào đó, nó quyết định rằng một số chuỗi sẽ được giải mã nhưng không được giải mã khác. Bây giờ chúng ta chỉ có thể tiền tố với chính mình là "file:///"
, tuy nhiên điều này không mang theo các đường dẫn UNC như \\remote\share\foo.txt
vào tài khoản - những gì dường như được chấp nhận chung trên Windows là biến chúng thành các url giả dạng file://remote/share/foo.txt
, vì vậy chúng ta nên tính đến tốt.
EscapeUriString
cũng có vấn đề là nó không thoát khỏi ký tự '#'
. Có vẻ như vào thời điểm này, chúng tôi không còn cách nào khác ngoài việc tạo ra phương pháp riêng của mình từ đầu. Vì vậy, đây là những gì tôi đề xuất:
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();
}
Điều này cố ý để lại + và: không được mã hóa như thường được thực hiện trên Windows. Nó cũng chỉ mã hóa latin1 vì Internet Explorer không thể hiểu các ký tự unicode trong url của tệp nếu chúng được mã hóa.
Và tệp đó in: /// c:/foo phải không? – knocte
Ý tôi là, nếu "chuyển đổi" được in ... – knocte
'var path = new Uri (" file: /// C: /whatever.txt ") .LocalPath;' biến Uri trở lại thành một tệp địa phương quá cho bất kỳ ai cần điều này. – Pondidum