Uzyskaj nazwę pliku z ciągu URI w C #

206

Mam tę metodę pobierania nazwy pliku z identyfikatora URI ciągu. Co mogę zrobić, aby był bardziej wytrzymały?

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
źródło

Odpowiedzi:

388

Możesz po prostu utworzyć obiekt System.Uri i użyć IsFile, aby sprawdzić, czy jest to plik, a następnie Uri.LocalPath, aby wyodrębnić nazwę pliku.

Jest to znacznie bezpieczniejsze, ponieważ zapewnia również sposób sprawdzenia ważności identyfikatora URI.


Edytuj w odpowiedzi na komentarz:

Aby uzyskać tylko pełną nazwę pliku, użyłbym:

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

Wykonuje to wszystkie sprawdzanie błędów i jest neutralne dla platformy. Wszystkie specjalne przypadki zostaną załatwione szybko i łatwo.

Reed Copsey
źródło
Zgadzam się, powinieneś naprawdę użyć klasy Uri, ponieważ już to robi dla ciebie. +1
Doctor Jones
2
Tak, ale potrzebuję tylko nazwy pliku, a nie pełnej ścieżki pliku. Czy nie zostałem jeszcze, aby zrobić ten krok na Uri.LocalPath?
paulwhit,
2
@paulwhit: W takim przypadku należy użyć Path.GetFileName na wynikach Uri.LocalPath. Jest to całkowicie bezpieczny, sprawdzony sposób obsługi. Zmienię swoją odpowiedź, aby to uwzględnić. Zobacz: msdn.microsoft.com/en-us/library/…
Reed Copsey
49
isFile wydaje się patrzeć tylko na schemat. Zatem: „ www / myFile.jpg ” zwraca false, „plik: //www/something.jpg” zwraca true, więc w tym przypadku jest bezużyteczny.
dethSwatch
6
Uważaj również na kwerendę. http://www.test.com/file1.txt?a=bspowodujefile1.txt?a=b
Julian
75

Uri.IsFile nie działa z adresami URL http. Działa tylko w przypadku „file: //”. From MSDN : „Właściwość IsFile jest prawdziwa, gdy właściwość Schemat jest równa UriSchemeFile.” Więc nie możesz na tym polegać.

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
Le Zhang
źródło
Uri.LocalPath dokonuje konwersji specyficznych dla systemu Windows i nie działa poprawnie w środowisku innym niż Windows. Zobacz moją odpowiedź poniżej, aby uzyskać przenośny sposób na zrobienie tego.
Kostub Deshmukh
Chociaż nie można użyć Uri.IsFiledo testowania adresu URL / schematu http, można skutecznie wyodrębnić nazwę pliku z adresu URL http, używającSystem.IO.Path.GetFileName(url);
Alex Pandrea
50

Większość innych odpowiedzi jest niekompletna lub nie dotyczy rzeczy następujących po ścieżce (ciąg zapytania / skrót).

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

Wyniki testu:

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
źródło
7
Dlaczego miałoby to GetFileNameFromUrl("test")spowodować, "test.xml" czy jest to tylko literówka?
ckittel
27

Przyjęta odpowiedź jest problematyczna dla adresów URL http. Ponadto Uri.LocalPathdokonuje konwersji specyficznych dla systemu Windows i, jak ktoś zauważył, pozostawia tam ciągi zapytań. Lepszym sposobem jest użycieUri.AbsolutePath

Prawidłowy sposób to zrobić dla adresów URL http:

Uri uri = new Uri(hreflink);
string filename = System.IO.Path.GetFileName(uri.AbsolutePath);
Kostub Deshmukh
źródło
7
Zwróć uwagę, że w przypadku takich adresów URL, które uciekłyby w http://example.com/dir/hello%20world.txtten sposób, zwracane byłyby takie hello%20world.txtsame Uri.LocalPathmetodyhello world.txt
Jeff Moser
22

Myślę, że zrobi to, czego potrzebujesz:

var uri = new Uri(hreflink);
var filename = uri.Segments.Last();
Zeus82
źródło
2
Wygląda to na eleganckie rozwiązanie, ale pamiętaj, że działa ono tylko na bezwzględnych identyfikatorach URI i zwraca zakodowaną / Uri.UnescapeDataString()zmienioną wartość (użyj, aby zmienić% 20 i + na spacje).
Ronald
8
using System.IO;

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

To oczywiście zakłada, że ​​parsowałeś nazwę pliku.

EDYCJA 2:

using System.IO;

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

To powinno obsługiwać spacje i tym podobne w nazwie pliku.

Mike Hofer
źródło
3
Dwukropki nie są akceptowane w ścieżkach na wszystkich platformach, więc tego rodzaju hack może się nie powieść, powiedzmy, Mono.NET działający na wariancie * nix. Lepiej korzystać z System.Uri, ponieważ jest on specjalnie zaprojektowany do robienia tego, czego potrzebuje OP.
richardtallent
1
Ważny punkt! Zawsze zapominam o Mono. Myślałem o przestrzeniach i tym podobnych, ale nie o dwukropkach.
Mike Hofer
2

to moja próbka, której możesz użyć:

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

Stosowanie:

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

Prosty i bezpośredni:

            Uri uri = new Uri(documentAttachment.DocumentAttachment.PreSignedUrl);
            fileName = Path.GetFileName(uri.LocalPath);
Gregory
źródło