【问题标题】:How to download image from URL如何从 URL 下载图像
【发布时间】:2014-09-07 23:13:01
【问题描述】:

如果 url 在链接末尾没有图像格式,有没有办法直接从 c# 中的 url 下载图像?网址示例:

https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t34.0-12/10555140_10201501435212873_1318258071_n.jpg?oh=97ebc03895b7acee9aebbde7d6b002bf&oe=53C9ABB0&__gda__=1405685729_110e04e71d969d392b63b27ec4f4b24a

当网址以图像格式结尾时,我知道如何下载图像。例如:

http://img1.wikia.nocookie.net/__cb20101219155130/uncyclopedia/images/7/70/Facebooklogin.png

【问题讨论】:

    标签: c# url download


    【解决方案1】:

    根据您是否知道图像格式,您可以使用以下方法:

    下载图片到文件,知道图片格式

    using (WebClient webClient = new WebClient()) 
    {
       webClient.DownloadFile("http://yoururl.com/image.png", "image.png") ; 
    }
    

    在不知道图像格式的情况下将图像下载到文件

    您可以使用Image.FromStream 加载任何类型的常用位图(jpg、png、bmp、gif、...),它会自动检测文件类型,您甚至不需要检查 url 扩展名(这不是一个很好的做法)。例如:

    using (WebClient webClient = new WebClient()) 
    {
        byte [] data = webClient.DownloadData("https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t34.0-12/10555140_10201501435212873_1318258071_n.jpg?oh=97ebc03895b7acee9aebbde7d6b002bf&oe=53C9ABB0&__gda__=1405685729_110e04e71d9");
    
       using (MemoryStream mem = new MemoryStream(data)) 
       {
           using (var yourImage = Image.FromStream(mem)) 
           { 
              // If you want it as Png
               yourImage.Save("path_to_your_file.png", ImageFormat.Png) ; 
    
              // If you want it as Jpeg
               yourImage.Save("path_to_your_file.jpg", ImageFormat.Jpeg) ; 
           }
       } 
    
    }
    

    注意:如果下载的内容不是已知的图像类型,Image.FromStream 可能会抛出 ArgumentException。

    检查this reference on MSDN 以查找所有可用格式。 这里参考WebClientBitmap

    【讨论】:

    • 请注意,您需要“使用 System.Drawing;”对于 Image.FromStream()
    • 请注意,除了要求图像库检测图像格式之外,您还可以查看响应标头以查看源认为图像使用的格式webClient.ResponseHeaders["Content-Type"]
    • 这也比将压缩图像扩展为未压缩的位图对象更节省内存,并允许您以原始格式保存图像及其原始压缩等。
    【解决方案2】:

    简单 您可以使用以下方法。

    using (WebClient client = new WebClient()) 
    {
        client.DownloadFile(new Uri(url), @"c:\temp\image35.png");
        // OR 
        client.DownloadFileAsync(new Uri(url), @"c:\temp\image35.png");
    }
    

    这些方法与 DownloadString(..) 和 DownloadStringAsync(...) 几乎相同。他们将文件存储在 Directory 中而不是 C# 字符串中,并且在 URi 中不需要 Format 扩展

    如果您不知道图片的格式(.png、.jpeg 等)

    public void SaveImage(string imageUrl, string filename, ImageFormat format)
    {    
        WebClient client = new WebClient();
        Stream stream = client.OpenRead(imageUrl);
        Bitmap bitmap;  bitmap = new Bitmap(stream);
    
        if (bitmap != null)
        {
            bitmap.Save(filename, format);
        }
            
        stream.Flush();
        stream.Close();
        client.Dispose();
    }
    

    使用它

    try
    {
        SaveImage("--- Any Image URL---", "--- Any Image Path ---", ImageFormat.Png)
    }
    catch(ExternalException)
    {
        // Something is wrong with Format -- Maybe required Format is not 
        // applicable here
    }
    catch(ArgumentNullException)
    {   
        // Something wrong with Stream
    }
    

    【讨论】:

    • @Arsman Ahmad 这是一个完全不同的问题,应该在其他地方寻找或询问。此线程用于下载单个图像。
    • 我认为它必须是'public void SaveImage(string imageUrl, string filename, ImageFormat format)'
    【解决方案3】:

    .net Framework 允许 PictureBox 控件从 url 加载图像

    并在Laod Complete Event中保存图像

    protected void LoadImage() {
     pictureBox1.ImageLocation = "PROXY_URL;}
    
    void pictureBox1_LoadCompleted(object sender, AsyncCompletedEventArgs e) {
       pictureBox1.Image.Save(destination); }
    

    【讨论】:

      【解决方案4】:

      试试这个对我有用

      把这个写在你的控制器里

      public class DemoController: Controller
      
              public async Task<FileStreamResult> GetLogoImage(string logoimage)
              {
                  string str = "" ;
                  var filePath = Server.MapPath("~/App_Data/" + SubfolderName);//If subfolder exist otherwise leave.
                  // DirectoryInfo dir = new DirectoryInfo(filePath);
                  string[] filePaths = Directory.GetFiles(@filePath, "*.*");
                  foreach (var fileTemp in filePaths)
                  {
                        str= fileTemp.ToString();
                  }
                      return File(new MemoryStream(System.IO.File.ReadAllBytes(str)), System.Web.MimeMapping.GetMimeMapping(str), Path.GetFileName(str));
              }
      

      这是我的看法

      <div><a href="/DemoController/GetLogoImage?Type=Logo" target="_blank">Download Logo</a></div>
      

      【讨论】:

        【解决方案5】:

        对于想要下载图像而不将其保存到文件的任何人:

        Image DownloadImage(string fromUrl)
        {
            using (System.Net.WebClient webClient = new System.Net.WebClient())
            {
                using (Stream stream = webClient.OpenRead(fromUrl))
                {
                    return Image.FromStream(stream);
                }
            }
        }
        

        【讨论】:

          【解决方案6】:

          我发现的大多数帖子在第二次迭代后都会超时。特别是如果您像我一样遍历一堆图像。所以这里改进上面的建议是整个方法:

          public System.Drawing.Image DownloadImage(string imageUrl)
              {
                  System.Drawing.Image image = null;
          
                  try
                  {
                      System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(imageUrl);
                      webRequest.AllowWriteStreamBuffering = true;
                      webRequest.Timeout = 30000;
                      webRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
                      webRequest.ServicePoint.MaxIdleTime = 5000;
          
                      using (System.Net.WebResponse webResponse = webRequest.GetResponse())
                      {
          
                          using (System.IO.Stream stream = webResponse.GetResponseStream())
                          {
                              image = System.Drawing.Image.FromStream(stream);
                          }
                      }
          
                      webRequest.ServicePoint.CloseConnectionGroup(webRequest.ConnectionGroupName);
                      webRequest = null; 
                  }
                  catch (Exception ex)
                  {
                      throw new Exception(ex.Message, ex);
          
                  }
          
          
                  return image;
              }
          

          【讨论】:

            【解决方案7】:

            .NET 这些年来发生了一些变化,使得这篇文章中的其他答案已经过时了:

            • 他们使用来自System.DrawingImage(不适用于.NET Core)来查找图像格式
            • 他们使用System.Net.WebClient,即deprecated

            我们不建议您将WebClient 类用于新开发。相反,请使用 System.Net.Http.HttpClient 类。

            .NET Core 异步解决方案

            获取文件扩展名

            获取文件扩展名的第一部分是从 URL 中删除所有不必要的部分。 我们可以使用 Uri.GetLeftPart() 和 UriPartial.Path 来获取从 SchemePath 的所有内容。
            换句话说,https://www.example.com/image.png?query&amp;with.dots 变成了https://www.example.com/image.png

            之后,我们可以使用Path.GetExtension() 仅获取扩展名(在我之前的示例中,.png)。

            var uriWithoutQuery = uri.GetLeftPart(UriPartial.Path);
            var fileExtension = Path.GetExtension(uriWithoutQuery);
            

            下载图片

            从这里开始应该是直截了当的。用HttpClient.GetByteArrayAsync下载图片,创建路径,确保目录存在,然后将字节写入File.WriteAllBytesAsync()路径

            private async Task DownloadImageAsync(string directoryPath, string fileName, Uri uri)
            {
                using var httpClient = new HttpClient();
            
                // Get the file extension
                var uriWithoutQuery = uri.GetLeftPart(UriPartial.Path);
                var fileExtension = Path.GetExtension(uriWithoutQuery);
            
                // Create file path and ensure directory exists
                var path = Path.Combine(directoryPath, $"{fileName}{fileExtension}");
                Directory.CreateDirectory(directoryPath);
            
                // Download the image and write to the file
                var imageBytes = await httpClient.GetByteArrayAsync(uri);
                await File.WriteAllBytesAsync(path, imageBytes);
            }
            

            请注意,您需要以下 using 指令。

            using System;
            using System.IO;
            using System.Threading.Tasks;
            using System.Net.Http;
            

            示例用法

            var folder = "images";
            var fileName = "test";
            var url = "https://cdn.discordapp.com/attachments/458291463663386646/592779619212460054/Screenshot_20190624-201411.jpg?query&with.dots";
            
            await DownloadImageAsync(folder, fileName, new Uri(url));
            

            注意事项

            • 为每个方法调用创建一个新的HttpClient 是不好的做法。它应该在整个应用程序中重复使用。我写了一个ImageDownloader(50 行)的简短示例,其中包含更多正确重用HttpClient 并正确处理它的文档,您可以找到here

            【讨论】:

            • 认为您的代码中有一个小错字。在DownloadImageAsync 中,朝向底部的线不应该是await httpClient,而不是await _httpClient
            • 感谢@MattWelke,我认为这是全班大意的剩余部分。将来您应该可以直接根据您的建议编辑帖子:)
            • 这次没让我编辑。建议编辑缺乏声誉?
            • 我见过他
            【解决方案8】:

            这个方法对我有用,

            我从here得到了主要代码

            然后使用这个fix

            我能够制作一种方法来绕过可怕的禁止 403 错误

            方法如下

                private static void DownloadImage(string url, string saveFilename)
                {
                    var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
                    // we need the user agent and default credentials if not,
                    //  we get a forbidden request 303 error, which pretty much means the server thinks we are a bot -- which we are.... hehehehehehe
                    httpWebRequest.UserAgent = "Case Banana"; // note -- this string can be anything you like, I recommend making it atleast 10 characters
                    httpWebRequest.UseDefaultCredentials = true;
            
                    var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                    if ((httpWebResponse.StatusCode != HttpStatusCode.OK &&
                        httpWebResponse.StatusCode != HttpStatusCode.Moved &&
                        httpWebResponse.StatusCode != HttpStatusCode.Redirect)
                        || !httpWebResponse.ContentType.StartsWith("image", StringComparison.OrdinalIgnoreCase))
                    {
                        return;
                    }
            
                    using (var stream = httpWebResponse.GetResponseStream())
                    {
                        using (var fileStream = File.OpenWrite(saveFilename))
                        {
                            var bytes = new byte[4096];
                            var read = 0;
                            do
                            {
                                if (stream == null)
                                {
                                    continue;
                                }
                                read = stream.Read(bytes, 0, bytes.Length);
                                fileStream.Write(bytes, 0, read);
                            } while (read != 0);
                        }
                    }
                }
            

            【讨论】:

              【解决方案9】:

              每个人都给出了很好的解决方案,但是每个人给出的所有解决方案背后都有一个主要问题,如果图像托管在 https 上,它不会创建 SSL/TLS 安全通道那么,我们应该怎么做呢?答案很简单,只需在创建 WebClient 请求之前添加这两行

              ServicePointManager.Expect100Continue = true;
              ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
              

              【讨论】:

                猜你喜欢
                • 2019-12-24
                • 1970-01-01
                • 2020-12-28
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-09-27
                • 2017-01-31
                • 2014-03-12
                相关资源
                最近更新 更多