Получить имя файла из строки URI в С#

У меня есть этот метод для захвата имени файла из строки 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;
}

person paulwhit    schedule 09.07.2009    source источник


Ответы (9)


Вы можете просто создать объект System.Uri и использовать IsFile, чтобы убедиться, что это файл, а затем Uri.LocalPath, чтобы извлечь имя файла.

Это намного безопаснее, так как также дает вам возможность проверить действительность URI.


Изменить в ответ на комментарий:

Чтобы получить только полное имя файла, я бы использовал:

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

Это делает всю проверку ошибок за вас и не зависит от платформы. Все особые случаи решаются за вас быстро и легко.

person Reed Copsey    schedule 09.07.2009
comment
Я согласен, вам действительно следует использовать класс Uri, поскольку он уже делает это за вас. +1 - person Doctor Jones; 09.07.2009
comment
Да, как бы просто это ни казалось, класс Uri имеет множество предварительно свернутых полезных вещей для синтаксического анализа/валидации/кодирования. - person STW; 09.07.2009
comment
Верно, но мне нужно только имя файла, а не полный путь к файлу. Разве мне еще не осталось сделать этот шаг на Uri.LocalPath? - person paulwhit; 10.07.2009
comment
@paulwhit: в этом случае вы должны использовать Path.GetFileName для результатов Uri.LocalPath. Это полностью безопасный, проверенный способ обращения с ним. Я отредактирую свой ответ, чтобы включить это. См.: msdn.microsoft.com/en-us/ библиотека/ - person Reed Copsey; 10.07.2009
comment
Отлично работает для абсолютных URL-адресов, но не работает для относительных. Класс Uri очень ограничен при работе с относительными URL-адресами. - person Tom; 17.09.2009
comment
Как сделать int в wp7, похоже Path.GetFileName недоступен. Кто-нибудь может посоветовать, как это сделать? - person masiboo; 13.08.2011
comment
isFile смотрит только на схему. Итак: www/myFile.jpg возвращает false, file://www/something.jpg возвращает true, так что это бесполезно в данном случае. - person dethSwatch; 22.10.2011
comment
@RAJ... я бы только что задал новый вопрос - person Reed Copsey; 06.07.2012
comment
Стоит отметить, что Uri может содержать такие символы, как и ‹, которые не могут находиться в путях файловой системы. Класс Path проверяет эти недопустимые символы и выдает исключение, если они существуют. Использование Uri.LocalPath не удаляет эти символы. Я написал сообщить о проблеме - person Kam Figy; 16.06.2013
comment
Также остерегайтесь строки запроса. http://www.test.com/file1.txt?a=b приведет к file1.txt?a=b - person Julian; 10.03.2015
comment
Не помогло http://url/start.aspx#/_catalogs/masterpage/my.master, сейчас использую: filename = System.IO.Path.GetFileName(strMasterPageURL.Split('/').Last()); - person David; 11.06.2015
comment
Кроме того, Path.GetFullPath не работал для файла://localhost/C:/Users/username/path/to/. Мне пришлось добавить «путь = uri.LocalPath.Replace(\\\\localhost\\, );». Не так элегантно. - person Jahmic; 25.09.2016
comment
Примечание. Это дает только имя файла (как задается вопрос), а не полный путь... Если вы после этого, попробуйте: System.IO.Path.GetFullPath(uri.AbsolutePath); - person andrew pate; 23.05.2017

Uri.IsFile не работает с URL-адресами http. Это работает только для "file://". Из MSDN: " Свойство IsFile имеет значение true, если свойство Scheme равно UriSchemeFile". Так что вы не можете полагаться на это.

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
person Le Zhang    schedule 19.02.2014
comment
Uri.LocalPath выполняет преобразования, специфичные для Windows, и работает неправильно в среде, отличной от Windows. См. Мой ответ ниже для портативного способа сделать это. - person Kostub Deshmukh; 11.01.2016
comment
Хотя вы не можете использовать Uri.IsFile для тестирования URL-адреса/схемы http, вы можете успешно извлечь имя файла из URL-адреса http, используя System.IO.Path.GetFileName(url); - person Alex Pandrea; 30.01.2019

Большинство других ответов либо неполные, либо не касаются вещей, следующих после пути (строка запроса/хэш).

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/");              // ""
person Ronnie Overby    schedule 01.11.2016
comment
Почему GetFileNameFromUrl("test") приводит к "test.xml" Или это просто опечатка? - person ckittel; 28.09.2018
comment
Не работает с .NET Core 3.0 (строка запроса не удаляется из пути) - person Alexandre Daubricourt; 18.11.2020
comment
@AlexandreDaubricourt Я только что проверил на netcore 3.0, 3.1 и net5.0 (все на Windows), и результат был правильным, без изменений. Не работает ли код на другой ОС под netcore 3.0? - person Ronnie Overby; 19.11.2020

Принятый ответ проблематичен для URL-адресов http. Кроме того, Uri.LocalPath выполняет преобразования, специфичные для Windows, и, как кто-то указал, что оставляет там строки запроса. Лучше использовать Uri.AbsolutePath.

Правильный способ сделать это для URL-адресов http:

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
person Kostub Deshmukh    schedule 15.09.2015
comment
Обратите внимание, что для экранированных URL-адресов, таких как http://example.com/dir/hello%20world.txt, это вернет hello%20world.txt, тогда как подход Uri.LocalPath вернет hello world.txt. - person Jeff Moser; 02.08.2017

Я думаю, что это сделает то, что вам нужно:

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();
person Zeus82    schedule 03.02.2017
comment
Это действительно выглядит элегантным решением, но имейте в виду, что оно работает только с абсолютными URI и возвращает закодированное/экранированное значение (используйте Uri.UnescapeDataString() для замены %20 и + на пробелы). - person Ronald; 06.03.2019

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("/", "\\"));
}

Это должно обрабатывать пробелы и тому подобное в имени файла.

person Mike Hofer    schedule 09.07.2009
comment
Двоеточия недопустимы в путях на всех платформах, поэтому такой хак может не сработать, скажем, на Mono.NET, работающем на варианте *nix. Лучше использовать System.Uri, так как он специально разработан для того, что нужно OP. - person richardtallent; 09.07.2009
comment
Верный момент! Я всегда забываю о Моно. Я думал о пробелах и тому подобном, но не о двоеточиях. - person Mike Hofer; 09.07.2009

это мой образец, который вы можете использовать:

        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");
person Ali Yousefi    schedule 28.01.2018

Просто и прямо вперед:

            Uri uri = new Uri(documentAttachment.DocumentAttachment.PreSignedUrl);
            fileName = Path.GetFileName(uri.LocalPath);
person Gregory    schedule 17.10.2019

По состоянию на 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);
}
person Alexandre Daubricourt    schedule 17.11.2020