代码之家  ›  专栏  ›  技术社区  ›  Tinister

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

  •  181
  • Tinister  · 技术社区  · 16 年前

    .NET框架是否有任何转换路径的方法(例如 "C:\whatever.txt" )到文件URI(例如 "file:///C:/whatever.txt" )?

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

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

    6 回复  |  直到 8 年前
        1
  •  265
  •   Pierre Arnaud    12 年前

    这个 System.Uri 构造函数能够解析完整的文件路径并将其转换为URI样式的路径。因此,您只需执行以下操作:

    var uri = new System.Uri("c:\\foo");
    var converted = uri.AbsoluteUri;
    
        2
  •  32
  •   poizan42    9 年前

    似乎没人意识到 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
    

    这种回报 “文件:///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 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中的Unicode字符(如果编码)。

        3
  •  7
  •   KyleMit Steven Vachon    11 年前

    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

        4
  •  4
  •   Bob Stine    8 年前

    上面的解决方案不能在Linux上工作。

    使用.NET核心,尝试执行 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"

        5
  •  3
  •   Gavin Greenwalt    11 年前

    至少在.NET 4.5+中,您还可以执行以下操作:

    var uri = new System.Uri("C:\\foo", UriKind.Absolute);
    
        6
  •  1
  •   IS4    8 年前

    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函数设法对特殊字符进行编码,但未对特定于Unicode的字符进行编码,这与 尿嘧啶尿路感染 建构者。在那种情况下, 阿贝特鲁里 包含正确编码的URL,而 原始字符串 可用于保留Unicode字符。

    推荐文章