将文件路径转换为文件URI?

时间:2009-10-09 22:44:24

标签: c# .net path uri

.NET Framework是否有任何方法可以将路径(例如"C:\whatever.txt")转换为文件URI(例如"file:///C:/whatever.txt")?

System.Uri类具有相反的(从文件URI到绝对路径),但我没有找到转换为文件URI的任何内容。

此外,这是 ASP.NET应用程序。

7 个答案:

答案 0 :(得分:272)

System.Uri构造函数能够解析完整的文件路径并将它们转换为URI样式路径。所以你可以做到以下几点:

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

答案 1 :(得分:32)

没有人似乎意识到,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:///"前缀,但是这不能将\\remote\share\foo.txt之类的UNC路径考虑在内 - 在Windows上似乎普遍接受的是将它们转换为{{{}形式的伪URL 1}},所以我们也应该考虑到这一点。

file://remote/share/foo.txt也有一个问题,即它不会逃避EscapeUriString字符。在这一点上,我们似乎别无选择,只能从头开始制作我们自己的方法。所以这就是我的建议:

'#'

这故意留下+和:未编码,因为它似乎通常是在Windows上完成的。它也只对latin1进行编码,因为Internet Explorer无法理解文件URL中的unicode字符(如果它们是编码的)。

答案 2 :(得分: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

答案 3 :(得分:5)

上述解决方案无法在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"

答案 4 :(得分:3)

至少在.NET 4.5+中你也可以这样做:

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

答案 5 :(得分:1)

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 构造函数不同,使特定于Unicode的字符保持未编码状态。在这种情况下, AbsoluteUri 包含正确编码的URL,而 OriginalString 可用于保留Unicode字符。

答案 6 :(得分:0)

解决方法很简单。只需使用Uri()。ToString()方法,然后对空格进行百分比编码。

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

正确返回 file:/// C:/ my%20exampleㄓ.txt