Abrufen des Dateinamens von der URI-Zeichenfolge in C #

206

Ich habe diese Methode zum Abrufen des Dateinamens von einem String-URI. Was kann ich tun, um es robuster zu machen?

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
quelle

Antworten:

388

Sie können einfach ein System.Uri-Objekt erstellen und mithilfe von IsFile überprüfen, ob es sich um eine Datei handelt, und dann Uri.LocalPath den Dateinamen extrahieren.

Dies ist viel sicherer, da Sie damit auch die Gültigkeit des URI überprüfen können.


Als Antwort auf einen Kommentar bearbeiten:

Um nur den vollständigen Dateinamen zu erhalten, würde ich Folgendes verwenden:

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

Dies führt die gesamte Fehlerprüfung für Sie durch und ist plattformneutral. Alle Sonderfälle werden schnell und einfach für Sie erledigt.

Reed Copsey
quelle
Ich stimme dir zu, du solltest die Uri-Klasse wirklich benutzen, da sie dieses Zeug bereits für dich erledigt. +1
Doktor Jones
2
Richtig, aber ich brauche nur den Dateinamen, nicht den vollständigen Dateipfad. Bin ich nicht noch übrig, um diesen Schritt auf dem Uri.LocalPath zu machen?
Paulwhit
2
@paulwhit: In diesem Fall sollten Sie Path.GetFileName für die Ergebnisse von Uri.LocalPath verwenden. Dies ist eine absolut sichere und streng geprüfte Art, damit umzugehen. Ich werde meine Antwort bearbeiten, um dies einzuschließen. Siehe: msdn.microsoft.com/en-us/library/…
Reed Copsey
49
isFile scheint nur das Schema zu betrachten. Also: " www / myFile.jpg " gibt false zurück, "file: //www/something.jpg" gibt true zurück, daher ist es in diesem Fall nutzlos.
dethSwatch
6
Achten Sie auch auf einen Querystring. http://www.test.com/file1.txt?a=bwird infile1.txt?a=b
Julian
75

Uri.IsFile funktioniert nicht mit http-URLs. Es funktioniert nur für "file: //". Aus MSDN : "Die IsFile-Eigenschaft ist wahr, wenn die Scheme-Eigenschaft gleich UriSchemeFile ist." Darauf kann man sich also nicht verlassen.

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
Le Zhang
quelle
Uri.LocalPath führt Windows-spezifische Konvertierungen durch und funktioniert in einer Nicht-Windows-Umgebung nicht ordnungsgemäß. In meiner Antwort unten finden Sie eine tragbare Möglichkeit, dies zu tun.
Kostub Deshmukh
Während Sie nicht Uri.IsFilezum Testen einer http-URL / eines http-Schemas verwenden können, können Sie den Dateinamen erfolgreich aus einer http-URL extrahieren, indem SieSystem.IO.Path.GetFileName(url);
Alex Pandrea
50

Die meisten anderen Antworten sind entweder unvollständig oder befassen sich nicht mit Dingen, die nach dem Pfad kommen (Abfragezeichenfolge / 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);
}

Testergebnisse:

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
quelle
7
Warum sollte das dazu GetFileNameFromUrl("test")führen "test.xml" ? Oder ist das nur ein Tippfehler?
ckittel
27

Die akzeptierte Antwort ist für http-URLs problematisch. Darüber hinaus werden Uri.LocalPathWindows-spezifische Konvertierungen durchgeführt, und wie bereits erwähnt, bleiben dort Abfragezeichenfolgen. Ein besserer Weg ist zu verwendenUri.AbsolutePath

Der richtige Weg, dies für http-URLs zu tun, ist:

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
Kostub Deshmukh
quelle
7
Beachten Sie, dass für maskierte URLs wie http://example.com/dir/hello%20world.txtdiese zurückkehren würde, hello%20world.txtwährend der Uri.LocalPathAnsatz zurückkehren würdehello world.txt
Jeff Moser
22

Ich denke, das wird tun, was Sie brauchen:

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();
Zeus82
quelle
2
Dies sieht in der Tat wie eine elegante Lösung aus, aber denken Sie daran, dass dies nur für absolute URIs funktioniert und einen codierten / maskierten Wert zurückgibt (verwenden Sie Uri.UnescapeDataString(), um% 20 und + in Leerzeichen zu ändern).
Ronald
8
using System.IO;

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

Dies setzt natürlich voraus, dass Sie den Dateinamen analysiert haben.

EDIT # 2:

using System.IO;

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

Dies sollte Leerzeichen und dergleichen im Dateinamen behandeln.

Mike Hofer
quelle
3
Doppelpunkte sind in Pfaden auf allen Plattformen nicht akzeptabel, daher kann diese Art von Hack beispielsweise auf Mono.NET fehlschlagen, das auf einer * nix-Variante ausgeführt wird. Besser System.Uri verwenden, da es speziell für die Anforderungen des OP entwickelt wurde.
richardtallent
1
Ein gültiger Punkt! Ich vergesse immer Mono. Ich dachte an Räume und dergleichen, aber nicht an die Doppelpunkte.
Mike Hofer
2

Dies ist mein Beispiel, das Sie verwenden können:

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

Verwendung:

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

Einfach und unkompliziert:

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