简体   繁体   English

URL的Path.Combine(第2部分)

[英]Path.Combine for URLs (part 2)

For awhile now, I've been searching for a Path.Combine method that works on URLs. 一段时间以来,我一直在寻找适用于URL的Path.Combine方法。 This is similiar to Path.Combine for URLs? 与URL的Path.Combine类似 with one big difference. 有一个很大的区别。

I'll illustrate with an example. 我将以一个例子来说明。 Say we have a base url: http://example.com/somefolder and a file: foo.txt . 假设我们有一个基本网址: http://example.com/somefolderhttp://example.com/somefolder和一个文件: foo.txt Thus, the full path would be: http://example.com/somefolder/foo.txt . 因此,完整路径将是: http://example.com/somefolder/foo.txthttp://example.com/somefolder/foo.txt Sounds simple, right? 听起来很简单吧? Ha. 哈。

I tried the Uri class: Uri.TryCreate(new Uri("http://example.com/somefolder"), "foo.txt", out x); 我尝试了Uri类: Uri.TryCreate(new Uri("http://example.com/somefolder"), "foo.txt", out x); which resulted in "http://example.com/foo.txt" . 这导致了"http://example.com/foo.txt"

Then I tried Path: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt"); 然后我尝试了Path: System.IO.Path.Combine("http://example.com/somefolder", "foo.txt"); which resulted in "http://example.com/somefolder\\foo.txt" ... Closer, but still no. 这导致了"http://example.com/somefolder\\foo.txt" ...更近,但仍然没有。

For kicks, I then tried: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt") which resulted in "http://example.com/somefolder/foo.txt" . 对于踢,我然后尝试: System.IO.Path.Combine("http://example.com/somefolder/", "foo.txt")导致"http://example.com/somefolder/foo.txt"

The last one worked, but it's basically doing string concatenation at that point. 最后一个工作,但它基本上在那时进行字符串连接。

So I think I have two options: 所以我认为我有两个选择:

  • Use Path.Combine and replace all \\ with / 使用Path.Combine并将所有\\替换为/
  • Use basic string concatenation 使用基本字符串连接

Am I missing a built in framework method for this? 我错过了一个内置的框架方法吗?

UPDATE: The usage case I have is for downloading a bunch of files. 更新:我的用例是下载一堆文件。 My code looks like this: 我的代码看起来像这样:

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

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

I'm miffed at having to use string concat in the Uri constructor, as well having to check if the slash is needed (which I omitted in the code). 我不得不在Uri构造函数中使用字符串concat,并且还要检查是否需要斜杠(我在代码中省略了)。

It seems to me that what I'm trying to do would come up a lot, since the Uri class handles a lot of other protocols besides http. 在我看来,我想要做的事情会出现很多,因为Uri类除了http之外还处理很多其他协议。

Flurl [disclosure: I'm the author] is a tiny URL builder library that can fill the gap with its Url.Combine method: 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"

You can get it via NuGet: Install-Package Flurl . 你可以通过NuGet: Install-Package Flurl获得它。

I also wanted to point out that you can dramatically improve the efficiency of your code by downloading the files in parallel. 我还想指出,您可以通过并行下载文件来显着提高代码的效率。 There's a couple ways to do that. 有几种方法可以做到这一点。 If you're on .NET 4.5 or above and can rewrite downloadFile as an async method, then your best option would be to replace your for loop with something like this: 如果您使用的是.NET 4.5或更高版本并且可以将downloadFile重写为异步方法,那么您最好的选择是用以下内容替换for循环:

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

Otherwise, if you're stuck on .NET 4, you can still achieve parallelism easily by using Parallel.ForEach : 否则,如果你坚持使用.NET 4,你仍然可以通过使用Parallel.ForEach轻松实现并行化

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

This is how the Uri class works. 这就是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");  

Basically do it via string manipulation simplest and do 基本上通过最简单的字符串操作来做

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

If you want to find out more. 如果你想了解更多。 Check out this post C# Url Builder Class 看看这篇文章C#Url Builder Class

Updated answer 更新的答案

When referring to base uri it will always be http://example.com/ anything to the right is just path. 当提到基础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;
    }
}

I have a static method for this purpose: 我有一个静态方法用于此目的:

// 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;

}

Here is a LINQ version of something close to the above answer. 这是一个接近上述答案的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

Omg, why all of you write such complex code? 哦,为什么你们都写这么复杂的代码? It is very simple: 这很简单:

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

Example of use: 使用示例:

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

Result url is " http://something.com/task/status/dfgd/111/qqq " 结果网址是“ http://something.com/task/status/dfgd/111/qqq

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM