【问题标题】:Get file name from URI string in C#从 C# 中的 URI 字符串获取文件名
【发布时间】:2010-11-09 11:42:12
【问题描述】:

我有这种从字符串 URI 中获取文件名的方法。我该怎么做才能让它更健壮?

private string GetFileName(string hrefLink)
{
    string[] parts = hrefLink.Split('/');
    string fileName = "";

    if (parts.Length > 0)
        fileName = parts[parts.Length - 1];
    else
        fileName = hrefLink;

    return fileName;
}

【问题讨论】:

    标签: c# string uri filenames


    【解决方案1】:

    您可以只创建一个 System.Uri 对象,然后使用 IsFile 验证它是一个文件,然后使用 Uri.LocalPath 提取文件名。

    这样更安全,因为它还为您提供了检查 URI 有效性的方法。


    根据评论进行编辑:

    要获得完整的文件名,我会使用:

    Uri uri = new Uri(hreflink);
    if (uri.IsFile) {
        string filename = System.IO.Path.GetFileName(uri.LocalPath);
    }
    

    这会为您完成所有错误检查,并且与平台无关。所有特殊情况都会为您快速轻松地处理。

    【讨论】:

    • 我同意,您应该真正使用 Uri 类,因为它已经为您完成了这些工作。 +1
    • 对,但我只需要文件名,而不是完整的文件路径。我不是还在 Uri.LocalPath 上做那一步吗?
    • @paulwhit:在这种情况下,您应该对 Uri.LocalPath 的结果使用 Path.GetFileName。这是一种完全安全、经过严格检查的处理方式。我将编辑我的答案以包含此内容。见:msdn.microsoft.com/en-us/library/…
    • isFile 似乎只查看方案。所以:“www/myFile.jpg”返回false,“file://www/something.jpg”返回true,所以在这种情况下没用。
    • 还要注意查询字符串。 http://www.test.com/file1.txt?a=b 将导致 file1.txt?a=b
    【解决方案2】:

    Uri.IsFile 不适用于 http 网址。它仅适用于“file://”。 来自MSDN:“当 Scheme 属性等于 UriSchemeFile 时,IsFile 属性为 true。” 所以你不能依赖它。

    Uri uri = new Uri(hreflink);
    string filename = System.IO.Path.GetFileName(uri.LocalPath);
    

    【讨论】:

    • Uri.LocalPath 执行 Windows 特定的转换,并且在非 Windows 环境中无法正常工作。请参阅下面的答案,了解一种便携的方法。
    • 虽然您不能使用Uri.IsFile 对http URL/方案进行测试,但您可以使用System.IO.Path.GetFileName(url); 成功地从http URL 中提取文件名
    【解决方案3】:

    大多数其他答案要么不完整,要么不处理路径之后的内容(查询字符串/哈希)。

    readonly static Uri SomeBaseUri = new Uri("http://canbeanything");
    
    static string GetFileNameFromUrl(string url)
    {
        Uri uri;
        if (!Uri.TryCreate(url, UriKind.Absolute, out uri))
            uri = new Uri(SomeBaseUri, url);
    
        return Path.GetFileName(uri.LocalPath);
    }
    

    测试结果:

    GetFileNameFromUrl("");                                         // ""
    GetFileNameFromUrl("test");                                     // "test"
    GetFileNameFromUrl("test.xml");                                 // "test.xml"
    GetFileNameFromUrl("/test.xml");                                // "test.xml"
    GetFileNameFromUrl("/test.xml?q=1");                            // "test.xml"
    GetFileNameFromUrl("/test.xml?q=1&x=3");                        // "test.xml"
    GetFileNameFromUrl("test.xml?q=1&x=3");                         // "test.xml"
    GetFileNameFromUrl("http://www.a.com/test.xml?q=1&x=3");        // "test.xml"
    GetFileNameFromUrl("http://www.a.com/test.xml?q=1&x=3#aidjsf"); // "test.xml"
    GetFileNameFromUrl("http://www.a.com/a/b/c/d");                 // "d"
    GetFileNameFromUrl("http://www.a.com/a/b/c/d/e/");              // ""
    

    【讨论】:

    • 为什么GetFileNameFromUrl("test") 会导致"test.xml" 或者这只是一个错字?
    • 不适用于 .NET Core 3.0(查询字符串未从路径中删除)
    • @AlexandreDaubricourt 我刚刚在 netcore 3.0、3.1 和 net5.0(都在 Windows 上)上进行了测试,输出是正确的,没有任何变化。代码是否在 netcore 3.0 下的不同操作系统上失败?
    【解决方案4】:

    接受的答案对于 http url 是有问题的。此外,Uri.LocalPath 会进行 Windows 特定的转换,并且正如有人指出的那样,会在其中留下查询字符串。更好的方法是使用Uri.AbsolutePath

    对 http url 执行此操作的正确方法是:

    Uri uri = new Uri(hreflink);
    string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
    

    【讨论】:

    • 请注意,对于像http://example.com/dir/hello%20world.txt 这样的转义URL,这将返回hello%20world.txt,而Uri.LocalPath 方法将返回hello world.txt
    【解决方案5】:

    我认为这将满足您的需求:

    var uri = new Uri(hreflink);
    var filename = uri.Segments.Last();
    

    【讨论】:

    • 这看起来确实是一个优雅的解决方案,但请记住,这仅适用于绝对 URI 并返回编码/转义值(使用 Uri.UnescapeDataString() 将 %20 和 + 更改为空格)。
    【解决方案6】:
    using System.IO;
    
    private String GetFileName(String hrefLink)
    {
        return Path.GetFileName(hrefLink.Replace("/", "\\"));
    }
    

    当然,这假设您已解析出文件名。

    编辑#2:

    using System.IO;
    
    private String GetFileName(String hrefLink)
    {
        return Path.GetFileName(Uri.UnescapeDataString(hrefLink).Replace("/", "\\"));
    }
    

    这应该处理文件名中的空格等。

    【讨论】:

    • 冒号在所有平台上的路径中都是不可接受的,因此这种 hack 可能会在运行在 *nix 变体上的 Mono.NET 上失败。最好使用 System.Uri,因为它是专门为满足 OP 需要而设计的。
    • 一个有效的点!我总是忘记单声道。我想到了空格之类的东西,但没有想到冒号。
    【解决方案7】:

    这是我可以使用的示例:

            public static string GetFileNameValidChar(string fileName)
        {
            foreach (var item in System.IO.Path.GetInvalidFileNameChars())
            {
                fileName = fileName.Replace(item.ToString(), "");
            }
            return fileName;
        }
    
        public static string GetFileNameFromUrl(string url)
        {
            string fileName = "";
            if (Uri.TryCreate(url, UriKind.Absolute, out Uri uri))
            {
                fileName = GetFileNameValidChar(Path.GetFileName(uri.AbsolutePath));
            }
            string ext = "";
            if (!string.IsNullOrEmpty(fileName))
            {
                ext = Path.GetExtension(fileName);
                if (string.IsNullOrEmpty(ext))
                    ext = ".html";
                else
                    ext = "";
                return GetFileNameValidChar(fileName + ext);
    
            }
    
            fileName = Path.GetFileName(url);
            if (string.IsNullOrEmpty(fileName))
            {
                fileName = "noName";
            }
            ext = Path.GetExtension(fileName);
            if (string.IsNullOrEmpty(ext))
                ext = ".html";
            else
                ext = "";
            fileName = fileName + ext;
            if (!fileName.StartsWith("?"))
                fileName = fileName.Split('?').FirstOrDefault();
            fileName = fileName.Split('&').LastOrDefault().Split('=').LastOrDefault();
            return GetFileNameValidChar(fileName);
        }
    

    用法:

    var fileName = GetFileNameFromUrl("http://cdn.p30download.com/?b=p30dl-software&f=Mozilla.Firefox.v58.0.x86_p30download.com.zip");
    

    【讨论】:

      【解决方案8】:

      简单直接:

                  Uri uri = new Uri(documentAttachment.DocumentAttachment.PreSignedUrl);
                  fileName = Path.GetFileName(uri.LocalPath);
      

      【讨论】:

        【解决方案9】:

        截至 2020 年,处理查询字符串和编码 URL

        public static string GetFileNameFromUrl (string url)
        {
            var decoded = HttpUtility.UrlDecode(url);
        
            if (decoded.IndexOf("?") is {} queryIndex && queryIndex != -1)
            {
                decoded = decoded.Substring(0, queryIndex);
            }
        
            return Path.GetFileName(decoded);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-06-15
          • 1970-01-01
          • 2011-05-14
          • 1970-01-01
          相关资源
          最近更新 更多