[C#] 파일 경로를 파일 URI로 변환 하시겠습니까?

.NET Framework에 경로 (예 "C:\whatever.txt":)를 파일 URI (예 :)로 변환하는 방법이 "file:///C:/whatever.txt"있습니까?

선택 System.Uri의 클래스는 (절대 경로에 파일 URI)에서 반대가 있지만 아무것도까지 내가 파일 URI로 변환 찾을 수있다.

또한 이것은 ASP.NET 응용 프로그램 이 아닙니다 .



답변

System.Uri생성자는 전체 파일 경로를 분석하고 URI 스타일의 경로로를 설정하는 기능이 있습니다. 따라서 다음을 수행 할 수 있습니다.

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


답변

아무도 알지 못하는 것은 어떤 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을 형식의 의사 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의 유니 코드 문자를 이해할 수 없으므로 latin1 만 인코딩합니다.


답변

위의 솔루션은 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"


답변

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


답변

.NET 4.5 이상에서는 다음을 수행 할 수도 있습니다.

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


답변

구조에 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의 길이를 출력하므로 먼저 길이를 얻은 다음 버퍼를 할당하십시오.

일부 매우 특히 “\\ localhost를 \ 경로가”그냥 “: /// 경로 파일”로 변환된다 : 내가 가진 흥미로운 관찰하면서 “\\ 장치 \ 경로가”제대로 “// 장치 / 경로 파일”로 변환된다는 점이다 .

WinApi 함수는 특수 문자를 인코딩했지만 Uri 구성자 와 달리 유니 코드 관련 문자는 인코딩되지 않은 상태로 둡니다 . 이 경우 AbsoluteUri 에 올바르게 인코딩 된 URL이 포함되고 OriginalString 을 사용하여 유니 코드 문자를 유지할 수 있습니다.


답변

해결 방법은 간단합니다. 나중에 Uri (). ToString () 메서드와 퍼센트 인코딩 공백을 사용하십시오.

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

file : /// C : / my % 20example ㄓ .txt를 올바르게 반환 합니다.