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

206

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

Ответы:

388

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

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


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

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

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

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

Рид Копси
источник
Я согласен, вы должны действительно использовать класс Uri, так как он уже делает это для вас. +1
Доктор Джонс
2
Да, но мне просто нужно имя файла, а не полный путь к файлу. Разве мне не осталось сделать этот шаг на Uri.LocalPath?
Полуит
2
@paulwhit: в этом случае вы должны использовать Path.GetFileName по результатам Uri.LocalPath. Это абсолютно безопасный, проверенный способ обращения с ним. Я отредактирую свой ответ, чтобы включить это. См .: msdn.microsoft.com/en-us/library/…
Рид Копси,
49
isFile, кажется, смотрит только на схему. Итак: « www / myFile.jpg » возвращает false, «file: //www/something.jpg» возвращает true, поэтому в данном случае это бесполезно.
dethSwatch
6
Также остерегайтесь строки запроса. http://www.test.com/file1.txt?a=bприведет кfile1.txt?a=b
Джулиан
76

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

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
Ле Чжан
источник
Uri.LocalPath выполняет специфичные для Windows преобразования и работает некорректно в среде, отличной от Windows. Смотрите мой ответ ниже для портативного способа сделать это.
Костуб Дешмукх
Несмотря на то, что вы не можете использовать Uri.IsFileдля проверки URL-адреса / схемы http, вы можете успешно извлечь имя файла из http-адреса с помощьюSystem.IO.Path.GetFileName(url);
Alex
50

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

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/");              // ""
Ронни Оверби
источник
7
Почему это может GetFileNameFromUrl("test")привести "test.xml" к опечатке?
ckittel
27

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

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

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
Костуб Дешмукх
источник
7
Обратите внимание, что для экранированных URL-адресов подобное http://example.com/dir/hello%20world.txtвозвращалось бы, hello%20world.txtа Uri.LocalPathподход возвращалсяhello world.txt
Джефф Мозер
22

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

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();
Zeus82
источник
2
Это действительно выглядит как элегантное решение, но имейте в виду, что оно работает только с абсолютными URI и возвращает закодированное / экранированное значение (используйте Uri.UnescapeDataString()для изменения% 20 и + на пробелы).
Рональд
8
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("/", "\\"));
}

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

Майк Хофер
источник
3
Двоеточия недопустимы в путях на всех платформах, поэтому такой взлом может произойти, например, на Mono.NET, работающем в варианте * nix. Лучше использовать System.Uri, поскольку она специально разработана для того, чтобы делать то, что нужно ОП.
Richardtallent
1
Действительный пункт! Я всегда забываю о Моно. Я думал о пространствах и тому подобное, но не о двоеточиях.
Майк Хофер
2

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

        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");
Али Юсефи
источник
0

Просто и понятно:

            Uri uri = new Uri(documentAttachment.DocumentAttachment.PreSignedUrl);
            fileName = Path.GetFileName(uri.LocalPath);
Грегори
источник