Obter nome do arquivo da string URI em C #

206

Eu tenho esse método para pegar o nome do arquivo de um URI de seqüência de caracteres. O que posso fazer para torná-lo mais robusto?

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
fonte

Respostas:

388

Você pode criar um objeto System.Uri e usar o IsFile para verificar se é um arquivo e, em seguida, Uri.LocalPath para extrair o nome do arquivo.

Isso é muito mais seguro, pois fornece um meio de verificar a validade do URI também.


Edite em resposta ao comentário:

Para obter apenas o nome do arquivo completo, eu usaria:

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

Isso faz toda a verificação de erros para você e é neutro em plataforma. Todos os casos especiais são tratados para você de forma rápida e fácil.

Reed Copsey
fonte
Concordo que você realmente deve usar a classe Uri, pois ela já faz essas coisas para você. +1
Doctor Jones
2
Certo, mas eu só preciso do nome do arquivo, não do caminho completo do arquivo. Ainda não me resta dar esse passo no Uri.LocalPath?
22139 paulwhit
2
@paulwhit: Nesse caso, você deve usar Path.GetFileName nos resultados do Uri.LocalPath. Essa é uma maneira completamente segura e altamente verificada de lidar com isso. Vou editar minha resposta para incluir isso. Veja: msdn.microsoft.com/en-us/library/...
Reed Copsey
49
O isFile parece observar apenas o esquema. Então: " www / myFile.jpg " retorna false ", file: //www/something.jpg" retorna true, portanto é inútil neste caso.
dethSwatch
6
Também tenha cuidado com uma string de consulta. http://www.test.com/file1.txt?a=bresultará emfile1.txt?a=b
Julian
76

Uri.IsFile não funciona com URLs http. Funciona apenas para "file: //". Do MSDN : "A propriedade IsFile é verdadeira quando a propriedade Scheme é igual a UriSchemeFile." Então você não pode depender disso.

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
Le Zhang
fonte
O Uri.LocalPath faz conversões específicas do Windows e não funciona corretamente em um ambiente não Windows. Veja minha resposta abaixo para uma maneira portátil de fazer isso.
Kostub Deshmukh
Embora você não possa usar Uri.IsFilepara testar um URL / esquema http, é possível extrair com êxito o nome do arquivo de um URL http usandoSystem.IO.Path.GetFileName(url);
Alex Pandrea
50

A maioria das outras respostas está incompleta ou não lida com coisas que vêm após o caminho (string de consulta / hash).

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);
}

Resultado dos testes:

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/");              // ""
Ronnie Overby
fonte
7
Por que GetFileNameFromUrl("test")resultaria em "test.xml" Ou isso é apenas um erro de digitação?
Ckittel # 28/18
27

A resposta aceita é problemática para URLs http. Além disso, Uri.LocalPathfaz conversões específicas do Windows e, como alguém apontou, deixa as strings de consulta lá. Uma maneira melhor é usarUri.AbsolutePath

A maneira correta de fazer isso para URLs http é:

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
Kostub Deshmukh
fonte
7
Note-se que para URLs escaparam como http://example.com/dir/hello%20world.txtisso iria retornar hello%20world.txtao passo que a Uri.LocalPathabordagem voltariahello world.txt
Jeff Moser
22

Eu acho que isso fará o que você precisa:

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();
Zeus82
fonte
2
Parece uma solução elegante, mas lembre-se de que isso funciona apenas em URIs absolutos e retorna um valor codificado / escapado (use Uri.UnescapeDataString()para alterar% 20 e + para espaços).
Ronald
8
using System.IO;

private String GetFileName(String hrefLink)
{
    return Path.GetFileName(hrefLink.Replace("/", "\\"));
}

Isso pressupõe, é claro, que você analisou o nome do arquivo.

EDIT # 2:

using System.IO;

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

Isso deve lidar com espaços e similares no nome do arquivo.

Mike Hofer
fonte
3
Dois pontos não são aceitáveis ​​em caminhos em todas as plataformas; portanto, esse tipo de invasão pode falhar, digamos, no Mono.NET em execução em uma variante * nix. Melhor usar o System.Uri, pois foi projetado especificamente para fazer o que o OP precisa.
Richardtallent
1
Um ponto válido! Eu sempre esqueço o Mono. Pensei em espaços e coisas do gênero, mas não em dois pontos.
Mike Hofer
2

esta é minha amostra, você pode usar:

        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);
    }

Uso:

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

Simples e direto:

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