Was niemand zu bemerken scheint, ist, dass keiner der System.Uri
Konstruktoren bestimmte Pfade mit Prozentzeichen korrekt behandelt.
new Uri(@"C:\%51.txt").AbsoluteUri;
Dies gibt Ihnen "file:///C:/Q.txt"
statt "file:///C:/%2551.txt"
.
Keiner der Werte des veralteten dontEscape-Arguments macht einen Unterschied, und die Angabe von UriKind führt ebenfalls zum gleichen Ergebnis. Der Versuch mit dem UriBuilder hilft auch nicht:
new UriBuilder() { Scheme = Uri.UriSchemeFile, Host = "", Path = @"C:\%51.txt" }.Uri.AbsoluteUri
Dies kehrt "file:///C:/Q.txt"
ebenfalls zurück.
Soweit ich das beurteilen kann, fehlt dem Framework tatsächlich eine Möglichkeit, dies richtig zu machen.
Wir können es versuchen, indem wir die umgekehrten Schrägstriche durch vordere Schrägstriche ersetzen und den Pfad zu Uri.EscapeUriString
- dh vorgeben
new Uri(Uri.EscapeUriString(filePath.Replace(Path.DirectorySeparatorChar, '/'))).AbsoluteUri
Dies scheint auf den ersten zu arbeiten, aber wenn man es den Weg geben C:\a b.txt
dann Sie am Ende mit file:///C:/a%2520b.txt
statt file:///C:/a%20b.txt
- irgendwie entscheidet es , dass einige Sequenzen decodiert werden sollten , andere aber nicht. Jetzt könnten wir uns nur noch ein Präfix "file:///"
machen, dies \\remote\share\foo.txt
berücksichtigt jedoch nicht die UNC-Pfade wie - was unter Windows allgemein akzeptiert zu sein scheint, ist, sie in Pseudo-URLs des Formulars umzuwandeln file://remote/share/foo.txt
, daher sollten wir dies ebenfalls berücksichtigen.
EscapeUriString
hat auch das problem, dass es dem '#'
charakter nicht entgeht . An diesem Punkt scheinen wir keine andere Wahl zu haben, als unsere eigene Methode von Grund auf neu zu entwickeln. Das schlage ich also vor:
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();
}
Dies lässt absichtlich + und: unverschlüsselt, da dies unter Windows normalerweise so zu sein scheint. Es codiert auch nur latin1, da Internet Explorer Unicode-Zeichen in Datei-URLs nicht verstehen kann, wenn sie codiert sind.
var path = new Uri("file:///C:/whatever.txt").LocalPath;
verwandelt einen Uri wieder in einen lokalen Dateipfad für alle, die dies benötigen.