Obtenir le nom de fichier à partir de la chaîne URI en C #

206

J'ai cette méthode pour saisir le nom de fichier à partir d'un URI de chaîne. Que puis-je faire pour le rendre plus robuste?

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
la source

Réponses:

388

Vous pouvez simplement créer un objet System.Uri et utiliser IsFile pour vérifier qu'il s'agit d'un fichier, puis Uri.LocalPath pour extraire le nom de fichier.

C'est beaucoup plus sûr, car cela vous permet également de vérifier la validité de l'URI.


Modifier en réponse au commentaire:

Pour obtenir uniquement le nom de fichier complet, j'utiliserais:

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

Cela effectue toutes les vérifications d'erreurs pour vous et est neutre sur la plate-forme. Tous les cas spéciaux sont traités rapidement et facilement pour vous.

Reed Copsey
la source
Je suis d'accord, vous devriez vraiment utiliser la classe Uri car elle fait déjà ce genre de choses pour vous. +1
Doctor Jones
2
D'accord, mais j'ai juste besoin du nom du fichier, pas du chemin d'accès complet. Ne suis-je pas encore parti pour faire cette étape sur Uri.LocalPath?
paulwhit
2
@paulwhit: Dans ce cas, vous devez utiliser Path.GetFileName sur les résultats de Uri.LocalPath. Il s'agit d'une manière complètement sûre et hautement vérifiée de le manipuler. Je vais modifier ma réponse pour l'inclure. Voir: msdn.microsoft.com/en-us/library/…
Reed Copsey
49
isFile semble ne regarder que le schéma. Donc: " www / myFile.jpg " retourne false, "file: //www/something.jpg" retourne true, donc c'est inutile dans ce cas.
dethSwatch
6
Méfiez-vous également d'une chaîne de requête. http://www.test.com/file1.txt?a=bse traduira parfile1.txt?a=b
Julian
76

Uri.IsFile ne fonctionne pas avec les URL http. Cela ne fonctionne que pour "file: //". De MSDN : "La propriété IsFile est vraie lorsque la propriété Scheme est égale à UriSchemeFile." Vous ne pouvez donc pas dépendre de cela.

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
Le Zhang
la source
Uri.LocalPath effectue des conversions spécifiques à Windows et ne fonctionne pas correctement dans un environnement non Windows. Voir ma réponse ci-dessous pour un moyen portable de le faire.
Kostub Deshmukh
Bien que vous ne puissiez pas utiliser Uri.IsFilepour tester sur une URL / un schéma http, vous pouvez extraire avec succès le nom de fichier à partir d'une URL http en utilisantSystem.IO.Path.GetFileName(url);
Alex Pandrea
50

La plupart des autres réponses sont soit incomplètes, soit ne traitent pas de choses venant après le chemin (chaîne de requête / hachage).

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

Résultats de test:

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
la source
7
Pourquoi aurait pour GetFileNameFromUrl("test")résultat "test.xml" Ou est-ce juste une faute de frappe?
ckittel
27

La réponse acceptée est problématique pour les URL http. De Uri.LocalPathplus, les conversions spécifiques à Windows, et comme quelqu'un l'a souligné, y laissent des chaînes de requête. Une meilleure façon est d'utiliserUri.AbsolutePath

La bonne façon de procéder pour les URL http est:

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
Kostub Deshmukh
la source
7
Notez que pour les URL échappées comme http://example.com/dir/hello%20world.txtcelle-ci, le retour serait hello%20world.txtalors que l' Uri.LocalPathapproche reviendraithello world.txt
Jeff Moser
22

Je pense que cela fera ce dont vous avez besoin:

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();
Zeus82
la source
2
Cela ressemble à une solution élégante, mais gardez à l'esprit que cela ne fonctionne que sur les URI absolus et renvoie une valeur codée / échappée (utilisez Uri.UnescapeDataString()pour changer% 20 et + en espaces).
Ronald
8
using System.IO;

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

Cela suppose, bien sûr, que vous avez analysé le nom du fichier.

EDIT # 2:

using System.IO;

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

Cela devrait gérer les espaces et autres dans le nom de fichier.

Mike Hofer
la source
3
Les deux-points ne sont pas acceptables dans les chemins d'accès sur toutes les plates-formes, donc ce type de piratage peut échouer, par exemple, Mono.NET fonctionnant sur une variante * nix. Mieux vaut utiliser System.Uri car il est spécialement conçu pour faire ce dont l'OP a besoin.
richardtallent
1
Un point valable! J'oublie toujours Mono. J'ai pensé aux espaces et autres, mais pas aux deux points.
Mike Hofer
2

voici mon échantillon que vous pouvez utiliser:

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

Usage:

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

Simple et direct:

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