2013-08-01 10 views
15

Od jakiegoś czasu szukam metody Path.Combine, która działa na adresy URL. Jest to podobne do Path.Combine for URLs? z jedną dużą różnicą.Path.Combine for URLs (part 2)

Zilustruję przykładem. Załóżmy, że mamy adres bazowy: http://example.com/somefolder i plik: foo.txt. Tak więc pełną ścieżką będzie: http://example.com/somefolder/foo.txt. Brzmi prosto, prawda? Ha.

Próbowałem klasy Uri: Uri.TryCreate(new Uri("http://example.com/somefolder"), "foo.txt", out x);, co dało w wyniku "http://example.com/foo.txt".

Potem próbowałem Ścieżka: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt");, która zakończyła się "http://example.com/somefolder\foo.txt" ... Bliżej, ale nadal nie.

Za kopnięcia próbowałem następnie: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt"), co dało w wyniku "http://example.com/somefolder/foo.txt".

Ten ostatni zadziałał, ale w zasadzie to robi ciągłe łączenie w tym punkcie.

Więc myślę, że mam dwie opcje:

  • Zastosowanie Path.Combine i zastąpić wszystkie \ z/
  • używać podstawowych połączonego łańcucha znaków

jestem brakuje wbudowany w metodzie ramowej dla to?

AKTUALIZACJA: Przypadek użycia, który mam, służy do pobierania wielu plików. Mój kod wygląda następująco:

public void Download() 
    { 
     var folder = "http://example.com/somefolder"; 
     var filenames = getFileNames(folder); 

     foreach (var name in filenames) 
     { 
      downloadFile(new Uri(folder + "/" + name)); 
     } 
    } 

jestem dotknięty przy konieczności korzystania ciąg concat w konstruktora Uri, jak również konieczności sprawdzenia, czy potrzebne jest ukośnik (które pominąłem w kodzie).

Wydaje mi się, że to, co próbuję zrobić, bardzo by się pojawiło, ponieważ klasa Uri obsługuje wiele innych protokołów poza http.

Odpowiedz

15

Flurl [ujawnienie: Jestem autora] jest mały budowniczy URL biblioteki, które mogą wypełnić lukę z jego metody Url.Combine:

string url = Url.Combine("http://www.foo.com/", "/too/", "/many/", "/slashes/", "too", "few"); 
// result: "http://www.foo.com/too/many/slashes/too/few" 

Można ją uzyskać poprzez Nuget: Install-Package Flurl.

Chciałbym również podkreślić, że możesz znacznie zwiększyć wydajność swojego kodu, pobierając pliki równolegle. Jest kilka sposobów na zrobienie tego. Jeśli jesteś na .NET 4.5 lub wyżej i może przepisać downloadFile jako metody asynchronicznego, wówczas najlepszym rozwiązaniem byłoby, aby zastąpić swoją pętlę for z mniej więcej tak:

var tasks = filenames.Select(f => downloadFileAsync(Url.Combine(folder, f))); 
await Task.WhenAll(tasks); 

przeciwnym razie, jeśli utkniesz na .NET 4, nadal można osiągnąć równoległość z łatwością za pomocą Parallel.ForEach:

Parallel.ForEach(filenames, f => downloadFile(Url.Combine(folder, f))); 
+0

Rzeczywiście, zsynchronizowałem pobieranie z ForEach. Po prostu to wyciąłem, ponieważ nie miało to znaczenia dla pytania. Interesujący link. Sprawdzę to i ewentualnie zmienię akceptowaną odpowiedź. – Xcelled194

+0

Na jakiej licencji jest podany kod? czy mogę go użyć na moim zastrzeżonym kodzie? – Jack

+1

Absolutnie. [Licencja MIT] (http://choosealicense.com/licenses/mit/), więc jest tak liberalna, jak to tylko możliwe. Nie możesz mnie pozwać. :) –

6

Tak działa klasa Uri.

var otherUri = new Uri("http://example.com/somefolder")); 
// somefolder is just a path 
var somefolder = otherUri.GetComponents(UriComponents.PathAndQuery, UriFormat.UriEscaped); 

// example one 
var baseUri = new Uri("http://example.com/"); 
var relativeUri = new Uri("somefolder/file.txt",UriKind.Relative); 
var fullUri = new Uri(baseUri, relativeUri); 

// example two 
var baseUri = new Uri("http://example.com/somefolder"); 
var relativeUri = new Uri("somefolder/file.txt",UriKind.Relative); 
var fullUri = new Uri(baseUri, relativeUri); 

// example three 
var baseUri = new Uri("http://example.com/"); 
var fullUri = new Uri(baseUri, "somefolder/file.txt"); 

Zasadniczo to zrobić poprzez ciąg manipulacji najprostszym i zrobić

var isValid = Uri.TryCreate(..., out myUri); 

Jeśli chcesz dowiedzieć się więcej. Sprawdź ten post C# Url Builder Class

Updated odpowiedź

W odniesieniu do podstawowego URI zawsze będzie http://example.com/ coś po prawej stronie jest po prostu droga.

void Main() 
{ 
    var ub = new UriBuilder("http://example.com/somefolder"); 
    ub.AddPath("file.txt"); 
      var fullUri = ub.Uri; 
} 
public static class MyExtensions 
{ 
    public static UriBuilder AddPath(this UriBuilder builder, string pathValue) 
    { 
    var path = builder.Path; 

    if (path.EndsWith("/") == false) 
    { 
     path = path + "/"; 
    } 

    path += Uri.EscapeDataString(pathValue); 

    builder.Path = path; 
    } 
} 
+0

Niestety, link (i przykłady), który pisał nie robić to, co chcę. Po prostu chcę wziąć podstawową ścieżkę URI i dołączyć do niej nazwę pliku. Używam prostej konkatenacji ciągów, ale nie mogę uwierzyć, że takie proste (typowe) użycie nie jest obsługiwane przez klasę URI. Zaktualizuję wpis przykładowym użytkowaniem i szczegółami mora. – Xcelled194

+0

Intencja klas uri po prostu nie jest tym, czego szukasz. Zaktualizowano odpowiedzi, aby pomóc Ci osiągnąć to, czego chcesz. – defong

+0

Wygląda na to, że brakuje dużej dziury w ramie ... Może JonSkeet zrobił coś, żeby ją podłączyć ... – Xcelled194

1

mam statycznej metody do tego celu:

// Combines urls like System.IO.Path.Combine 
// Usage: this.Literal1.Text = CommonCode.UrlCombine("http://stackoverflow.com/", "/questions ", " 372865", "path-combine-for-urls"); 
public static string UrlCombine(params string[] urls) { 
    string retVal = string.Empty; 
    foreach (string url in urls) 
    { 
     var path = url.Trim().TrimEnd('/').TrimStart('/').Trim(); 
     retVal = string.IsNullOrWhiteSpace(retVal) ? path : new System.Uri(new System.Uri(retVal + "/"), path).ToString(); 
    } 
    return retVal; 

} 
1

Oto wersja LINQ czegoś zbliżonego do powyższej odpowiedzi.

+0

Nie potrzebujesz całego tego przycinania ... 'Trim ('', '/')' zrobi to. –

+0

To działałoby dla spacji i/To nie jest identyczne z poprzednim kodem, ponieważ Trim zajmuje się całą białą przestrzenią, a nie tylko spacjami. Ale podoba mi się i adres URL powinien działać dobrze. – GenuineRex

0

Omg, dlaczego wszyscy z was napisali tak skomplikowany kod? To bardzo proste:

private string CombineUrl(params string[] urls) 
{ 
    string result = ""; 

    foreach (var url in urls) 
    { 
     if (result.Length > 0 && url.Length > 0) 
      result += '/'; 

     result += url.Trim('/'); 
    } 

    return result; 
} 

Przykład zastosowania:

var methodUrl = CombineUrl("http://something.com", "/task/status/", "dfgd/", "/111", "qqq"); 

Wynik url jest "http://something.com/task/status/dfgd/111/qqq"

+1

Co się stanie, jeśli adres URL zakończy się ukośnikiem? Na przykład 'CombineUrl (" http://example.com ","/task/status/");' zwraca 'http: // example.com/task/status' zamiast' http://example.com/task/status/'jak można się spodziewać. – styfle