如何使用 httpwebrequest 将图像从网站拉到本地文件

Posted

技术标签:

【中文标题】如何使用 httpwebrequest 将图像从网站拉到本地文件【英文标题】:How to use httpwebrequest to pull image from website to local file 【发布时间】:2011-01-23 00:16:34 【问题描述】:

我正在尝试使用本地 c# 应用程序将一些图像从网站拉到本地计算机上的文件中。我正在使用下面列出的代码。我尝试了 ASCII 编码和 UTF8 编码,但最终文件不正确。有谁看到我做错了什么?当我将地址放入浏览器时,该网址是有效且正确的,并且可以很好地显示图像。

    private void button1_Click(object sender, EventArgs e)
    
        HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");

        // returned values are returned as a stream, then read into a string
        String lsResponse = string.Empty;
        HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse();
        using (StreamReader lxResponseStream = new StreamReader(lxResponse.GetResponseStream()))
        
            lsResponse = lxResponseStream.ReadToEnd();
            lxResponseStream.Close();
        

        byte[] lnByte = System.Text.UTF8Encoding.UTF8.GetBytes(lsResponse);

        System.IO.FileStream lxFS = new FileStream("34891.jpg", FileMode.Create);
        lxFS.Write(lnByte, 0, lnByte.Length);
        lxFS.Close();

        MessageBox.Show("done");
    

【问题讨论】:

顺便说一句,您的 HttpWebResponse 和 FileStream 对象需要使用块,因为它们实现了 IDisposable。另外,为什么要初始化 lsResponse,因为它总是会被设置(否则会抛出异常)。最后,我建议你停止使用匈牙利符号(lxFS),你不需要前缀就可以知道每个对象的类型。只需将鼠标悬停在它上面。 【参考方案1】:

好图:D

尝试使用以下代码:

您需要使用 BinaryReader,因为图像文件是二进制数据,因此未以 UTF 或 ASCII 编码

编辑:使用'ified

HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create(
"http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");

// returned values are returned as a stream, then read into a string
String lsResponse = string.Empty;
using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse())
   using (BinaryReader reader = new BinaryReader(lxResponse.GetResponseStream())) 
      Byte[] lnByte = reader.ReadBytes(1 * 1024 * 1024 * 10);
      using (FileStream lxFS = new FileStream("34891.jpg", FileMode.Create)) 
          lxFS.Write(lnByte, 0, lnByte.Length);
      
   

MessageBox.Show("done");

【讨论】:

-1:我知道您只是在更改他提供的代码,但您应该真正改进它以防止资源泄漏。告诉他在哪里放置using 块,我会删除我的反对票。 我喜欢使用 .Close 方法而不是使用块。根据 msdn: Close 的这种实现调用 Dispose 方法传递一个真值。所以根据资源泄漏我们应该没问题。使用块更安全还是比 .Close() 更有优势? (编辑:忘记关门了) @henchman:using 块确保 Dispose 将被调用,即使存在未处理的异常。在几乎所有适当的情况下不使用它们是一个坏习惯(您创建一个实现IDisposable 的类的实例,只将它分配给局部变量,并且不要从创建它的方法中返回它,当它是不是 WCF 代理实例)。如果你经常使用它,你不会忘记它一次或两次。 感谢各位的回答。我认为约翰对 using 块的看法是正确的,即使使用 .close 方法也是如此。我认为当变量超出范围时立即进行处理,而不是在例程结束时进行处理。我还认为我将处理例程的 ReadBytes 部分,以分块读取流直到它结束,而不是假定 10MB 的限制。 请告诉我们您针对 10MB 限制的解决方案 - 我找不到这种类型的阅读器/流组合的解决方案。 Stream.Length 不可用。 Using-blocks 也比 .Close() 看起来更好,尽管当更多的块将被聚合到缩进时会很有趣:-)【参考方案2】:

好的,这是最终答案。它使用内存流作为缓冲来自响应流的数据的一种方式。

    private void button1_Click(object sender, EventArgs e)
    
        byte[] lnBuffer;
        byte[] lnFile;

        HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create("http://www.productimageswebsite.com/images/stock_jpgs/34891.jpg");
        using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse())
        
            using (BinaryReader lxBR = new BinaryReader(lxResponse.GetResponseStream()))
            
                using (MemoryStream lxMS = new MemoryStream())
                
                    lnBuffer = lxBR.ReadBytes(1024);
                    while (lnBuffer.Length > 0)
                    
                        lxMS.Write(lnBuffer, 0, lnBuffer.Length);
                        lnBuffer = lxBR.ReadBytes(1024);
                    
                    lnFile = new byte[(int)lxMS.Length];
                    lxMS.Position = 0;
                    lxMS.Read(lnFile, 0, lnFile.Length);
                
            
        

        using (System.IO.FileStream lxFS = new FileStream("34891.jpg", FileMode.Create))
        
            lxFS.Write(lnFile, 0, lnFile.Length);
        
        MessageBox.Show("done");
    

【讨论】:

哦,是的...忘记删除 close 方法,因为我正在使用 using 块。【参考方案3】:

答案的变体,使用 async await 异步文件 I/O。 See Async File I/O 为什么这很重要。

下载 png 并使用 BinaryReader/Writer 写入磁盘

string outFile = System.IO.Path.Combine(outDir, fileName);

// Download file
var request = (HttpWebRequest) WebRequest.Create(imageUrl);

using (var response = await request.GetResponseAsync())
    using (var reader = new BinaryReader(response.GetResponseStream())) 

        // Read file 
        Byte[] bytes = async reader.ReadAllBytes();

        // Write to local folder 
        using (var fs = new FileStream(outFile, FileMode.Create)) 
            await fs.WriteAsync(bytes, 0, bytes.Length);
        
    

读取所有字节扩展方法

public static class Extensions 

    public static async Task<byte[]> ReadAllBytes(this BinaryReader reader)
    
        const int bufferSize = 4096;
        using (var ms = new MemoryStream())
        
            byte[] buffer = new byte[bufferSize];
            int count;
            while ((count = reader.Read(buffer, 0, buffer.Length)) != 0) 
                await ms.WriteAsync(buffer, 0, count);
            
            return ms.ToArray();
        
    

【讨论】:

【参考方案4】:

您可以使用以下方法从网站下载图像并使用 Image 类进行保存:

WebRequest req = WebRequest.Create(imageUrl);
WebResponse resp = req.GetResponse();
Image img = Image.FromStream(resp.GetResponseStream());
img.Save(filePath +  fileName + ".jpg");

【讨论】:

以上是关于如何使用 httpwebrequest 将图像从网站拉到本地文件的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 HttpWebRequest 模拟浏览器文件上传

上传Image MultiPart Form HTTPWebRequest - 将图像数据转换为字符串?

如何使用 HttpWebRequest 将数据发布到 MVC 控制器?

如何使用 c# 使用 httpwebrequest 从 json api 获取数据?

如何防止 HttpWebRequest 的数据包碎片

如何通过httpwebrequest访问使用证书登录的网站