파일 경로를 파일 URI로 변환 하시겠습니까?


201

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

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

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

답변:


291

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"
쿼드 코더

# 문자가 포함 된 경로에서도 작동하지 않습니다.
루이스

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을 형식의 의사 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 만 인코딩합니다.


자유 라이센스로 이것을 포함하는 너겟이 있습니까? 이것은 프레임 워크에 존재하는 적절한 방법이없고 유감
스럽게도

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

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

나는 이것이 특수 문자 처리에 대해 말하는 대답에 설명 된 것과 동일한 문제로 고통 받고 있다고 확신합니다 .
binki

4

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

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

1
UriFormatException언젠가 는 위험을 감수하지 않습니까?
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의 길이를 출력하므로 먼저 길이를 얻은 다음 버퍼를 할당하십시오.

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

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


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.