Obtener el nombre del archivo de la cadena URI en C #

206

Tengo este método para tomar el nombre del archivo de un URI de cadena. ¿Qué puedo hacer para que sea más 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
fuente

Respuestas:

388

Puede crear un objeto System.Uri y usar IsFile para verificar que es un archivo, luego Uri.LocalPath para extraer el nombre de archivo.

Esto es mucho más seguro, ya que también le proporciona un medio para verificar la validez del URI.


Editar en respuesta al comentario:

Para obtener solo el nombre de archivo completo, usaría:

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

Esto realiza todas las comprobaciones de errores por usted y es neutral para la plataforma. Todos los casos especiales se manejan por usted de manera rápida y fácil.

Reed Copsey
fuente
Estoy de acuerdo, realmente deberías usar la clase Uri ya que ya hace esto por ti. +1
Doctor Jones
2
Correcto, pero solo necesito el nombre del archivo, no la ruta completa del archivo. ¿Todavía no me queda hacer ese paso en el Uri.LocalPath?
paulwhit
2
@paulwhit: en ese caso, debe usar Path.GetFileName en los resultados de Uri.LocalPath. Esta es una forma completamente segura y altamente controlada de manejarlo. Editaré mi respuesta para incluir esto. Ver: msdn.microsoft.com/en-us/library/…
Reed Copsey
49
Parece que isFile solo mira el esquema. Entonces: " www / myFile.jpg " devuelve falso, "file: //www/something.jpg" devuelve verdadero, por lo que es inútil en este caso.
dethSwatch
66
También tenga cuidado con una cadena de consulta. http://www.test.com/file1.txt?a=bresultará enfile1.txt?a=b
Julian
76

Uri.IsFile no funciona con URL http. Solo funciona para "archivo: //". Desde MSDN : "La propiedad IsFile es verdadera cuando la propiedad Scheme es igual a UriSchemeFile". Entonces no puedes depender de eso.

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
Le Zhang
fuente
Uri.LocalPath realiza conversiones específicas de Windows y no funciona correctamente en un entorno que no sea Windows. Vea mi respuesta a continuación para una forma portátil de hacer esto.
Kostub Deshmukh
Aunque no se puede utilizar Uri.IsFilea prueba en una dirección URL http / esquema, se puede extraer con éxito el nombre de archivo de una URL http usandoSystem.IO.Path.GetFileName(url);
Alex Pandrea
50

La mayoría de las otras respuestas están incompletas o no se ocupan de las cosas que siguen a la ruta (cadena 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);
}

Resultados de la prueba:

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
fuente
77
¿Por qué GetFileNameFromUrl("test")resultaría en "test.xml" O es solo un error tipográfico?
ckittel
27

La respuesta aceptada es problemática para las URL http. Además, Uri.LocalPathrealiza conversiones específicas de Windows y, como alguien señaló, deja cadenas de consulta allí. Una mejor manera es usarUri.AbsolutePath

La forma correcta de hacer esto para las URL http es:

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
Kostub Deshmukh
fuente
77
Tenga en cuenta que para las URL escapadas como http://example.com/dir/hello%20world.txtesta volvería, hello%20world.txtmientras que el Uri.LocalPathenfoque volveríahello world.txt
Jeff Moser
22

Creo que esto hará lo que necesitas:

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();
Zeus82
fuente
2
Esto parece una solución elegante, pero tenga en cuenta que esto solo funciona en URI absolutos y devuelve un valor codificado / escapado (use Uri.UnescapeDataString()para cambiar% 20 y + a espacios).
Ronald
8
using System.IO;

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

Esto supone, por supuesto, que ha analizado el nombre del archivo.

EDITAR # 2:

using System.IO;

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

Esto debería manejar espacios y similares en el nombre del archivo.

Mike Hofer
fuente
3
Los dos puntos no son aceptables en las rutas en todas las plataformas, por lo que este tipo de pirateo podría fallar en, por ejemplo, Mono.NET ejecutándose en una variante * nix. Es mejor usar System.Uri ya que está específicamente diseñado para hacer lo que el OP necesita.
richardtallent
1
Un punto valido! Siempre me olvido de Mono. Pensé en espacios y similares, pero no en los dos puntos.
Mike Hofer
2

esta es mi muestra que puedes 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
fuente
0

Simple y directo:

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