ファイルパスをファイルURIに変換しますか?


201

.NET Frameworkには、パス(例"C:\whatever.txt")をファイルURI(例"file:///C:/whatever.txt")に変換するメソッドがありますか?

System.Uriのクラスは(絶対パスにファイルURIから)の逆を持っているが、何も私の知る限りでは、ファイルURIに変換するために見つけることができないよう。

また、これはASP.NETアプリケーションではありません

回答:


292

System.Uriコンストラクタは、完全なファイルパスを解析し、URIの形式のパスにそれらを有効にする能力を持っています。したがって、次のことを実行できます。

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

78
var path = new Uri("file:///C:/whatever.txt").LocalPath;これを必要とする誰にとっても、Uriをローカルファイルパスに戻します。
ポンディダム

2
注として。これらの種類のUriは、セッションウィンドウでのVS出力およびR#ユニットテスト出力でクリック可能です
AlfeG

7
残念ながらこれは正しくありません。たとえば、new Uri(@"C:\%51.txt").AbsoluteUriあなたを与える"file:///C:/Q.txt"代わりに"file:///C:/%2551.txt"
poizan42

2
これは、スペースのあるパスでは機能しません。例: "C:\ test folder \ whatever.txt"
Quad Coders

また、これは#文字を含むパスでは機能しません。
ルイス

42

誰も気付いていないように見えるのは、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:///"自分自身でプレフィックスを付けることもできますが、これはUNCパス\\remote\share\foo.txtを考慮に入れることができません。Windowsで一般的に受け入れられているように見えるのは、それらをフォームの疑似URLに変換することなfile://remote/share/foo.txtので、それも考慮する必要があります。

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で通常行われている方法のように見えるためです。また、エンコードされている場合、Internet ExplorerはファイルURLのUnicode文字を理解できないため、latin1のみをエンコードします。


これをリベラルなライセンスで含む核心はありますか?これはフレームワークに存在する適切な方法がないのは残念です。copypastaを更新し続けることも難しい…
binki

4
MITライセンスの条件に基づいて上記のコードを使用できます(短いものでも著作権で保護されているはずですが、現在は明示的な許可が与えられています)
poizan42

9

上記のソリューションはLinuxでは機能しません。

.NET Coreを使用して実行しようとする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"


パスが絶対パスであることがわかっている場合は使用できますnew Uri("/path/to/file", UriKind.Absolute);
ミニジャック

8

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


2
AbsoluteUriスペースも%20にエンコードするため、正しいものです。
psulek 2015

これは、特殊文字の処理について説明している回答で説明されいるのと同じ問題に苦しんでいると確信しています。
binki

4

少なくとも.NET 4.5以降では、次のこともできます。

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

1
UriFormatException1日かかるリスクはありませんか?
berezovskyi

これも正しく機能せず、代わりにnew Uri(@"C:\%51.txt",UriKind.Absolute).AbsoluteUri返されます"file:///C:/Q.txt""file:///C:/%2551.txt"
poizan42

2

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の長さを出力するため、最初に長さを取得してからバッファーを割り当てます。

私が持っていたいくつかの非常に興味深い観察は、「\\ device \ path」が「file:// device / path」に正しく変換される一方で、具体的には「\\ localhost \ path」が単に「file:/// path」に変換されることです。

WinApi関数は特殊文字のエンコードに成功しましたが、Uriコンストラクターとは異なり、Unicode固有の文字はエンコードされません。その場合、AbsoluteUriには適切にエンコードされたURLが含まれますが、OriginalStringを使用してUnicode文字を保持できます。


0

回避策は簡単です。あとは、Uri()。ToString()メソッドを使用し、必要に応じて空白をパーセントでエンコードします。

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

適切にfile:/// C:/ my%20exampleㄓ.txtを返します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.