it-swarm.com.de

Dateipfad in eine Datei-URI konvertieren?

Verfügt .NET Framework über Methoden zum Konvertieren eines Pfads (z. B. "C:\whatever.txt") in eine Datei-URI (z. B. "file:///C:/whatever.txt")?

Die System.Uri -Klasse hat das Gegenteil (von einem Datei-URI zu einem absoluten Pfad), aber nichts, was ich für die Konvertierung in einen Datei-URI finden kann.

Dies ist auch keine ASP.NET-Anwendung.

190
Tinister

Das System.Uri -Konstruktor kann vollständige Dateipfade analysieren und in Pfade im URI-Stil umwandeln. Sie können also einfach Folgendes tun:

var uri = new System.Uri("c:\\foo");
var converted = uri.AbsoluteUri;
276
JaredPar

Was niemand zu bemerken scheint, ist, dass keiner der Konstruktoren System.Uri Bestimmte Pfade mit Prozentzeichen richtig verarbeitet.

new Uri(@"C:\%51.txt").AbsoluteUri;

Dies gibt Ihnen "file:///C:/Q.txt" Anstelle von "file:///C:/%2551.txt".

Keine der beiden Werte des veralteten dontEscape-Arguments hat einen Unterschied, und die Angabe von UriKind führt ebenfalls zu demselben Ergebnis. Der Versuch mit dem UriBuilder hilft auch nicht:

new UriBuilder() { Scheme = Uri.UriSchemeFile, Host = "", Path = @"C:\%51.txt" }.Uri.AbsoluteUri

Dies gibt ebenfalls "file:///C:/Q.txt" Zurück.

Soweit ich das beurteilen kann, fehlt dem Framework tatsächlich jede Möglichkeit, dies richtig zu machen.

Wir können es versuchen, indem wir die umgekehrten Schrägstriche durch Schrägstriche ersetzen und den Pfad zu Uri.EscapeUriString - d. H.

new Uri(Uri.EscapeUriString(filePath.Replace(Path.DirectorySeparatorChar, '/'))).AbsoluteUri

Dies scheint zunächst zu funktionieren, aber wenn Sie den Pfad C:\a b.txt Angeben, erhalten Sie file:///C:/a%2520b.txt Anstelle von file:///C:/a%20b.txt - irgendwie entscheidet es, dass einige Sequenzen sollten dekodiert werden, andere jedoch nicht. Jetzt können wir uns nur noch "file:///" Voranstellen, dies berücksichtigt jedoch keine UNC-Pfade wie \\remote\share\foo.txt - was unter Windows allgemein akzeptiert zu sein scheint, ist, sie in Pseudo-URLs des Formulars umzuwandeln file://remote/share/foo.txt, Also sollten wir das auch berücksichtigen.

EscapeUriString hat auch das Problem, dass das Zeichen '#' nicht ausgeblendet wird. Es scheint an diesem Punkt, dass wir keine andere Wahl haben, als unsere eigene Methode von Grund auf neu zu erstellen. 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();
}

Dabei bleiben absichtlich + und: unverschlüsselt, da dies unter Windows normalerweise der Fall zu sein scheint. Es codiert auch nur latin1, da Internet Explorer Unicode-Zeichen in Datei-URLs nicht versteht, wenn sie codiert sind.

33
poizan42

VB.NET:

Dim URI As New Uri("D:\Development\~AppFolder\Att\1.gif")

Unterschiedliche Ausgänge:

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

Einzeiler:

New Uri("D:\Development\~AppFolder\Att\1.gif").AbsoluteUri

Ausgabe: file:///D:/Development/~AppFolder/Att/1.gif

8
MrCalvin

Die oben genannten Lösungen funktionieren nicht unter Linux.

Bei Verwendung von .NET Core führt der Versuch, new Uri("/home/foo/README.md") auszuführen, zu einer Ausnahme:

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)
   ...

Sie müssen der CLR einige Hinweise geben, welche Art von URL Sie haben.

Das funktioniert:

Uri fileUri = new Uri(new Uri("file://"), "home/foo/README.md");

... und der von fileUri.ToString() zurückgegebene String ist "file:///home/foo/README.md"

Dies funktioniert auch unter Windows.

new Uri(new Uri("file://"), @"C:\Users\foo\README.md").ToString()

... gibt "file:///C:/Users/foo/README.md" aus

7
Bob Stine

Zumindest in .NET 4.5+ können Sie auch Folgendes tun:

var uri = new System.Uri("C:\\foo", UriKind.Absolute);
3
Gavin Greenwalt

rlCreateFromPath zur Rettung! Nun, nicht ganz, da es keine erweiterten und UNC-Pfadformate unterstützt, aber das ist nicht so schwer zu überwinden:

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);

Beginnt der Pfad mit einem speziellen Präfix, wird er entfernt. Obwohl in der Dokumentation nicht erwähnt, gibt die Funktion die Länge der URL aus, auch wenn der Puffer kleiner ist. Daher erhalte ich zuerst die Länge und ordne dann den Puffer zu.

Einige sehr interessante Beobachtungen, die ich gemacht habe, sind, dass "\\ device\path" korrekt in "file: // device/path" umgewandelt wurde, insbesondere " \\ localhost\path "wird in" file: /// path "umgewandelt.

Die WinApi-Funktion konnte zwar Sonderzeichen codieren, Unicode-spezifische Zeichen bleiben jedoch im Gegensatz zum Uri-Construtor unverschlüsselt. In diesem Fall enthält AbsoluteUri die ordnungsgemäß codierte URL, während OriginalString dies kann verwendet werden, um die Unicode-Zeichen beizubehalten.

1
IllidanS4

Die Problemumgehung ist einfach. Verwenden Sie einfach die Uri (). ToString () -Methode und codieren Sie anschließend gegebenenfalls Leerzeichen in Prozent.

string path = new Uri("C:\my exampleㄓ.txt").ToString().Replace(" ", "%20");

richtig zurück Datei: /// C:/mein% 20Beispiel ample .txt

0
ThingsHappen