.NET Framework에 경로 (예 "C:\whatever.txt"
:)를 파일 URI (예 :)로 변환하는 방법이 "file:///C:/whatever.txt"
있습니까?
선택 System.Uri의 클래스는 (절대 경로에 파일 URI)에서 반대가 있지만 아무것도까지 내가 파일 URI로 변환 찾을 수있다.
또한 이것은 ASP.NET 응용 프로그램 이 아닙니다 .
.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;
new Uri(@"C:\%51.txt").AbsoluteUri
당신을 제공 "file:///C:/Q.txt"
하는 대신"file:///C:/%2551.txt"
아무도 알지 못하는 것은 어떤 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"
new Uri("/path/to/file", UriKind.Absolute);
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
AbsoluteUri
공백도 % 20으로 인코딩하기 때문에 올바른 것입니다.
.NET 4.5 이상에서는 다음을 수행 할 수도 있습니다.
var uri = new System.Uri("C:\\foo", UriKind.Absolute);
UriFormatException
언젠가 는 위험을 감수하지 않습니까?
new Uri(@"C:\%51.txt",UriKind.Absolute).AbsoluteUri
반환을 "file:///C:/Q.txt"
대신"file:///C:/%2551.txt"
구조에 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 을 사용하여 유니 코드 문자를 유지할 수 있습니다.
var path = new Uri("file:///C:/whatever.txt").LocalPath;
Uri를 로컬 파일 경로로 다시 전환하십시오.