C# 将文件路径转换为文件 URI?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1546419/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert file path to a file URI?
提问by Tinister
Does the .NET Framework have any methods for converting a path (e.g. "C:\whatever.txt"
) into a file URI (e.g. "file:///C:/whatever.txt"
)?
.NET Framework 是否有任何将路径(例如"C:\whatever.txt"
)转换为文件 URI(例如"file:///C:/whatever.txt"
)的方法?
The System.Uriclass has the reverse (from a file URI to absolute path), but nothing as far as I can find for converting to a file URI.
该的System.Uri类有反向(从文件URI以绝对路径),但没有就我可以找到转换为文件URI。
Also, this is notan ASP.NET application.
此外,这不是ASP.NET 应用程序。
采纳答案by JaredPar
The System.Uri
constructor has the ability to parse full file paths and turn them into URI style paths. So you can just do the following:
该System.Uri
构造函数解析完整的文件路径,并把它们变成URI风格的路径的能力。因此,您只需执行以下操作:
var uri = new System.Uri("c:\foo");
var converted = uri.AbsoluteUri;
回答by MrCalvin
VB.NET:
VB.NET:
Dim URI As New Uri("D:\Development\~AppFolder\Att.gif")
Different outputs:
不同的输出:
URI.AbsolutePath -> D:/Development/~AppFolder/Att/1.gif
URI.AbsoluteUri -> file:///D:/Development/~AppFolder/Att/1.gif
URI.OriginalString -> D:\Development\~AppFolder\Att.gif
URI.ToString -> file:///D:/Development/~AppFolder/Att/1.gif
URI.LocalPath -> D:\Development\~AppFolder\Att.gif
One liner:
一个班轮:
New Uri("D:\Development\~AppFolder\Att.gif").AbsoluteUri
Output:
file:///D:/Development/~AppFolder/Att/1.gif
输出:
file:///D:/Development/~AppFolder/Att/1.gif
回答by Gavin Greenwalt
At least in .NET 4.5+ you can also do:
至少在 .NET 4.5+ 中,您还可以执行以下操作:
var uri = new System.Uri("C:\foo", UriKind.Absolute);
回答by poizan42
What no-one seems to realize is that none of the System.Uri
constructors correctly handles certain paths with percent signs in them.
似乎没有人意识到,没有一个System.Uri
构造函数正确处理某些带有百分号的路径。
new Uri(@"C:\%51.txt").AbsoluteUri;
This gives you "file:///C:/Q.txt"
instead of "file:///C:/%2551.txt"
.
这给你"file:///C:/Q.txt"
而不是"file:///C:/%2551.txt"
.
Neither values of the deprecated dontEscape argument makes any difference, and specifying the UriKind gives the same result too. Trying with the UriBuilder doesn't help either:
已弃用的 dontEscape 参数的值都没有任何区别,并且指定 UriKind 也会给出相同的结果。尝试使用 UriBuilder 也无济于事:
new UriBuilder() { Scheme = Uri.UriSchemeFile, Host = "", Path = @"C:\%51.txt" }.Uri.AbsoluteUri
This returns "file:///C:/Q.txt"
as well.
这也返回"file:///C:/Q.txt"
。
As far as I can tell the framework is actually lacking any way of doing this correctly.
据我所知,该框架实际上缺乏任何正确执行此操作的方法。
We can try to it by replacing the backslashes with forward slashes and feed the path to Uri.EscapeUriString
- i.e.
我们可以尝试通过用正斜杠替换反斜杠并将路径输入到Uri.EscapeUriString
- 即
new Uri(Uri.EscapeUriString(filePath.Replace(Path.DirectorySeparatorChar, '/'))).AbsoluteUri
This seems to work at first, but if you give it the path C:\a b.txt
then you end up with file:///C:/a%2520b.txt
instead of file:///C:/a%20b.txt
- somehow it decides that somesequences should be decoded but not others. Now we could just prefix with "file:///"
ourselves, however this fails to take UNC paths like \\remote\share\foo.txt
into account - what seems to be generally accepted on Windows is to turn them into pseudo-urls of the form file://remote/share/foo.txt
, so we should take that into account as well.
起初这似乎有效,但是如果你给它路径,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
also has the problem that it does not escape the '#'
character. It would seem at this point that we have no other choice but making our own method from scratch. So this is what I suggest:
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();
}
This intentionally leaves + and : unencoded as that seems to be how it's usually done on Windows. It also only encodes latin1 as Internet Explorer can't understand unicode characters in file urls if they are encoded.
这故意留下 + 和 : 未编码,因为这似乎是它通常在 Windows 上完成的方式。它还只对 latin1 进行编码,因为 Internet Explorer 无法理解文件 url 中的 unicode 字符(如果它们被编码)。
回答by Bob Stine
The solutions above do not work on Linux.
上述解决方案不适用于 Linux。
Using .NET Core, attempting to execute new Uri("/home/foo/README.md")
results in an exception:
使用 .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)
...
You need to give the CLR some hints about what sort of URL you have.
您需要向 CLR 提供一些有关您拥有的 URL 类型的提示。
This works:
这有效:
Uri fileUri = new Uri(new Uri("file://"), "home/foo/README.md");
...and the string returned by fileUri.ToString()
is "file:///home/foo/README.md"
...返回的字符串fileUri.ToString()
是"file:///home/foo/README.md"
This works on Windows, too.
这也适用于 Windows。
new Uri(new Uri("file://"), @"C:\Users\foo\README.md").ToString()
new Uri(new Uri("file://"), @"C:\Users\foo\README.md").ToString()
...emits "file:///C:/Users/foo/README.md"
...发出 "file:///C:/Users/foo/README.md"
回答by IllidanS4 wants Monica back
UrlCreateFromPathto the rescue! Well, not entirely, as it doesn't support extended and UNC path formats, but that's not so hard to overcome:
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);
In case the path starts with with a special prefix, it gets removed. Although the documentation doesn't mention it, the function outputs the length of the URL even if the buffer is smaller, so I first obtain the length and then allocate the buffer.
如果路径以特殊前缀开头,它将被删除。虽然文档没有提到,但是函数即使缓冲区更小,也会输出URL的长度,所以我先获取长度,然后分配缓冲区。
Some veryinteresting observation I had is that while "\\device\path" is correctly transformed to "file://device/path", specifically "\\localhost\path" is transformed to just "file:///path".
我有一些非常有趣的观察是,虽然“\\device\path”被正确转换为“file://device/path”,但特别是“\\localhost\path”被转换为“file:///path” .
The WinApi function managed to encode special characters, but leaves Unicode-specific characters unencoded, unlike the Uriconstrutor. In that case, AbsoluteUricontains the properly encoded URL, while OriginalStringcan be used to retain the Unicode characters.
WinApi 函数设法对特殊字符进行编码,但与Uri构造函数不同,未编码特定于 Unicode 的字符。在这种情况下,AbsoluteUri包含正确编码的 URL,而OriginalString可用于保留 Unicode 字符。
回答by ThingsHappen
The workaround is simple. Just use the Uri().ToString() method and percent-encode white-spaces, if any, afterwards.
解决方法很简单。之后只需使用 Uri().ToString() 方法和百分比编码空格,如果有的话。
string path = new Uri("C:\my exampleㄓ.txt").ToString().Replace(" ", "%20");
properly returns file:///C:/my%20exampleㄓ.txt
正确返回file:///C:/my%20exampleㄓ.txt