Path.Combine для URL-адресов (часть 2)
На какое-то время я искал метод Path.Combine, который работает с URL-адресами. Это похоже на Path.Combine для URL-адресов? с одной большой разницей.
Я проиллюстрирую пример. Скажем, у нас есть базовый url: http://example.com/somefolder
и файл: foo.txt
. Таким образом, полный путь: http://example.com/somefolder/foo.txt
. Звучит просто, не так ли? Ха.
Я попробовал класс Uri: Uri.TryCreate(new Uri("http://example.com/somefolder"), "foo.txt", out x);
, в результате чего "http://example.com/foo.txt"
.
Затем я попробовал Path: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt");
, в результате получив "http://example.com/somefolder\foo.txt"
... Ближе, но все же нет.
Для ударов я тогда попытался: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt")
, в результате чего "http://example.com/somefolder/foo.txt"
.
Последняя работала, но в основном выполняла конкатенацию строк в этой точке.
Итак, у меня есть два варианта:
- Использовать Path.Combine и заменить все \with/
- Использование основной конкатенации строк
Мне не хватает встроенного метода framework для этого?
ОБНОВЛЕНИЕ:. Я использую для загрузки кучу файлов. Мой код выглядит следующим образом:
public void Download()
{
var folder = "http://example.com/somefolder";
var filenames = getFileNames(folder);
foreach (var name in filenames)
{
downloadFile(new Uri(folder + "/" + name));
}
}
Мне посчастливилось использовать string concat в конструкторе Uri, а также проверить, нужна ли косая черта (которую я пропустил в коде).
Мне кажется, что то, что я пытаюсь сделать, будет очень много, так как класс Uri обрабатывает множество других протоколов, кроме http.
Ответы
Ответ 1
Flurl [раскрытие: я автор] - это крошечная библиотека построителей URL-адресов, которая может заполнить пробел с помощью метода 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"
Вы можете получить его через NuGet: Install-Package Flurl
.
Я также хотел указать, что вы можете значительно повысить эффективность своего кода, загрузив файлы параллельно. Там есть пара способов сделать это. Если вы используете .NET 4.5 или выше и можете переписать downloadFile
как метод async, то лучшим вариантом будет замена вашего цикла for
на что-то вроде этого:
var tasks = filenames.Select(f => downloadFileAsync(Url.Combine(folder, f)));
await Task.WhenAll(tasks);
В противном случае, если вы застряли на .NET 4, вы можете легко достичь parallelism, используя Parallel.ForEach:
Parallel.ForEach(filenames, f => downloadFile(Url.Combine(folder, f)));
Ответ 2
Вот как работает класс 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");
В основном делать это с помощью строковых манипуляций проще всего и делать
var isValid = Uri.TryCreate(..., out myUri);
Если вы хотите узнать больше.
Отметьте этот пост С# Url Builder Class
Обновленный ответ
Если ссылаться на базовый uri, он всегда будет http://example.com/ что-то справа - это просто путь.
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;
}
}
Ответ 3
У меня есть статический метод для этой цели:
// 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;
}
Ответ 4
Вот версия LINQ, близкая к вышеуказанному ответу.
public static string UrlCombine( this string root, params string[] parts)
{
return parts
.Select(part => part.Trim().TrimEnd('/').TrimStart('/').Trim())
.Aggregate(root, (current, path) => current + ("/" + path));
}
var x = "http://domain.com";
var p = "path";
var u = x.UrlCombine(p, "test.html"); // http://domain.com/path/test.html
Ответ 5
Омг, почему все вы пишете такой сложный код? Это очень просто:
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;
}
Пример использования:
var methodUrl = CombineUrl("http://something.com", "/task/status/", "dfgd/", "/111", "qqq");
Результат url - http://something.com/task/status/dfgd/111/qqq"