programing

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

elecom 2023. 5. 28. 19:59
반응형

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

.NET Framework)이 있습니까?"C:\whatever.txt"URI( URI(예: URI)로 합니다."file:///C:/whatever.txt")?

시스템.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를 지정하면 동일한 결과를 얻을 수 있습니다.URI Builder를 사용하는 것도 도움이 되지 않습니다.

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.txtfile:///C:/a%20b.txt어떤 식으로든 일부 시퀀스는 디코딩되어야 하지만 다른 시퀀스는 디코딩되지 않아야 한다고 결정합니다.이제 우리는 그냥 다음과 같이 접두사를 붙일 수 있습니다."file:///"은 우리 스스로, 우리경자신, 만이은것다 UNC로못합니와 못합니다.\\remote\share\foo.txt고려하여 - 되는 것으로 를 서려사항 - 에고로로허 - 으는용것되 - 적다일보으 - 이 - 로는것반 - 은의형유 - - ▁form로-▁into - ▁the다에ls고▁of 형식의 유사 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(윈도우)에서 일반적으로 수행되는 방식인 것처럼 보이기 때문에 의도적으로 + 및 :가 인코딩되지 않습니다.또한 latin1만 인코딩하여 Internet Explorer가 파일 URL의 유니코드 문자를 이해할 수 없도록 합니다.

위의 솔루션은 Linux에서 작동하지 않습니다.

Core를 하여 .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의 길이를 출력하기 때문에 저는 먼저 길이를 구한 다음 버퍼를 할당합니다.

"\\device\path"가 "file://device/path"로 올바르게 변환되는 반면, "\localhost\path"는 단지 "file:///path"로 변환된다는 것이 제가 가진 매우 흥미로운 관찰입니다.

WinApi 함수는 특수 문자를 인코딩하는 데 성공했지만 URI 생성자와 달리 유니코드 고유 문자는 인코딩되지 않은 상태로 유지됩니다.이 경우 AbsoluteUri에는 제대로 인코딩된 URL이 포함되지만 OriginalString을 사용하여 유니코드 문자를 유지할 수 있습니다.

불행하게도 @poizan42 답변은 우리가 유니코드 세계에 살고 있다는 사실을 고려하지 않으며 RFC3986에 따르면 너무 제한적입니다.@pierre-arnaud 및 @jaredpar의 허용된 답변은 시스템에 의존합니다.파일 이름의 가변성을 관리할 수 없을 정도로 URI의 구성 요소를 너무 많이 관리해야 하는 URI 생성자는 백분율 문자 및 기타 사례에서 제대로 작동하지 않습니다.다른 대답은 단순화되거나 단순히 유용하지 않습니다.가장 좋은 것은 @is4였을 것이지만, 이 게시물의 첫 번째 버전을 게시한 후 제가 작성한 테스트 케이스에서 함께 테스트해 보았는데 많은 유니코드 문자에서 실패했습니다.

저의 경우, 저는 @poizan42 코드와 무엇이 작동하고 무엇이 작동하지 않는지에 대한 다양한 답변을 조사하기 시작했고, 그래서 저는 약간 다른 접근법을 취했습니다.

먼저 입력 문자열을 유효한 파일 경로로 간주하여 모든 유효한 유니코드 문자와 대리 쌍을 사용하여 테스트에서 경로를 프로그래밍 방식으로 생성했습니다.이를 통해 적어도 Path는 확인했습니다.적어도 윈도우즈에서는 GetInvalidFileNameChars()가 올바른 집합을 반환하는 것 같습니다.그런 다음 https://www.ietf.org/rfc/rfc3986.txt 의 22페이지에서 찾을 수 있는 경로에 대한 ABNF 규칙에 따라 구현한 방법으로 이러한 경로를 전달했습니다.

UriBuilder가 생성한 결과와 그 결과를 비교하면 다음과 같습니다.

public static string FilePathToFileUrl(string path)
{
    return new UriBuilder("file",string.Empty)
        {
            Path = path
                .Replace("%",$"%{(int)'%':X2}")
                .Replace("[",$"%{(int)'[':X2}")
                .Replace("]",$"%{(int)']':X2}"),
        }
        .Uri
        .AbsoluteUri;
}

이는 완전히 최적화되지 않았으며 세 번의 교체를 수행하므로 스팬 또는 StringBuilder로 변환하십시오.

해결 방법은 간단합니다.URI()를 사용합니다.ToString() 메서드와 화이트스페이스(있는 경우)를 나중에 인코딩합니다.

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

파일을 올바르게 반환합니다.///C:/my%20 example{\}.txt

언급URL : https://stackoverflow.com/questions/1546419/convert-file-path-to-a-file-uri

반응형