如何使用HttpWebRequest/Response从Web服务器下载二进制(.exe)文件?

14

我正在编写一个程序,需要从网站下载一个 .exe 文件并将其保存到硬盘。这个 .exe 文件存储在我的网站上,它的URL如下(它不是真实的URI,只是为了解决这个问题而虚构的):

http://www.mysite.com/calc.exe

经过多次网络搜索和试验,这是我迄今为止想出的代码:

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(http://www.mysite.com/calc.exe);
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();               
StreamReader streamReader = new StreamReader(responseStream);
string s = streamReader.ReadToEnd();

你可以看到我正在使用 StreamReader 类来读取数据。调用 ReadToEnd 方法后,流阅读器是否包含我的 .exe 文件的(二进制)内容?我能否将 StreamReader 的内容写入一个名为 calc.exe 的文件中,并且成功下载了 .exe 文件吗?

我想知道为什么 StreamReaderReadToEnd 方法返回一个字符串。在我的情况下,这个字符串是否是 calc.exe 的二进制内容?

6个回答

13

WebClient是下载文件的最佳方法。但您可以使用以下方法异步地从Web服务器下载文件。

private static void DownloadCurrent()
{
    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("[url to download]");
    webRequest.Method = "GET";
    webRequest.Timeout = 3000;
    webRequest.BeginGetResponse(new AsyncCallback(PlayResponeAsync), webRequest);
}

private static void PlayResponeAsync(IAsyncResult asyncResult)
{
    long total = 0;
    long received = 0;
    HttpWebRequest webRequest = (HttpWebRequest)asyncResult.AsyncState;

    try
    {                    
        using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.EndGetResponse(asyncResult))
        {
            byte[] buffer = new byte[1024];

            FileStream fileStream = File.OpenWrite("[file name to write]");
            using (Stream input = webResponse.GetResponseStream())
            {        
                total = input.Length;

                int size = input.Read(buffer, 0, buffer.Length);
                while (size > 0)
                {
                    fileStream.Write(buffer, 0, size);
                    received += size;

                    size = input.Read(buffer, 0, buffer.Length);
                }
            }

            fileStream.Flush();
            fileStream.Close();
        }                 
    }
    catch (Exception ex)
    {
    }
}

这里有一个类似的帖子 - 如何使用httpwebrequest下载文件


4
感谢您的回答。在代码中,total = input.Length 这行代码存在一个不重要的错误。由于 input.Length 是长整型,因此 total 变量也必须是长整型。 - Alisettar Huseynli
请使用 webResponse.ContentLength 替代 input.Length - Sergio Cabral

9

StreamReader 是一个文本读取器的实现,即应该用于读取文本数据而不是二进制数据。在您的情况下,您应该直接使用底层响应流。

对于下载文件,最简单的方法是使用 WebClient.DownloadFile 方法。


非常感谢!我现在会查看WebClient.DownloadFile! - Jan Tacci
1
WebClient的DownloadFile方法可行,而且只需三行代码! - Jan Tacci

3
这应直接将文件保存在您的硬盘上。
using System.Net;
using (WebClient webClient = new WebClient ())
{
    webClient.DownloadFile("http://www.mysite.com/calc.exe", "calc.exe");
}

23
他正在询问 httpwebrequests 而不是 webclient。 - Georgi-it

1

我可能有点晚,但我也遇到了同样的问题,如果不在调试模式下运行,文件始终为0kb大小。这可能是一个相对简单的答案,但在属性下禁用“DEBUG-Constants”对我很有帮助。


1

不要使用StreamReader,而应该调用您的Stream对象的Read()方法。这将要求您提供一个byte[]缓冲区来填充读取数据,然后您可以使用StreamWriterFileStream将其写入磁盘。


我看到有人使用字节数组和循环读取流的示例,直到没有更多数据为止。我也试过了。这是我使用的循环:*while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)*。你建议我这样做吗? - Jan Tacci

0
我创建了一个带有事件的类,以便您可以跟踪下载进度:
using System;
using System.IO;
using System.Net;
using System.Net.Mime;

//event examples: https://www.tutorialsteacher.com/csharp/csharp-event

public class HttpWebRequestDownload
{
    private long _totalBytesLength = 0;
    private long _transferredBytes = 0;
    private int _transferredPercents => (int)((100 * _transferredBytes) / _totalBytesLength);
    private string _defaultDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    public string downloadedFilePath = String.Empty;

    public HttpWebRequestDownload(){
        //Windows 7 fix
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
    }

    public void DownloadFile(string url, string destinationDirectory = default)
    {
        string filename = "";
        if (destinationDirectory == default)
            destinationDirectory = _defaultDirectory;

        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Headers.Add("Cache-Control", "no-cache");
            request.Headers.Add("Cache-Control", "no-store");
            request.Headers.Add("Cache-Control", "max-age=1");
            request.Headers.Add("Cache-Control", "s-maxage=1");
            request.Headers.Add("Pragma", "no-cache");
            request.Headers.Add("Expires", "-1");

            if (!Directory.Exists(destinationDirectory))
            {
                Directory.CreateDirectory(destinationDirectory);
            }

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponseAsync().Result)
            {
                _totalBytesLength = response.ContentLength;

                string path = response.Headers["Content-Disposition"];
                if (string.IsNullOrWhiteSpace(path))
                {
                    var uri = new Uri(url);
                    filename = Path.GetFileName(uri.LocalPath);
                }
                else
                {
                    ContentDisposition contentDisposition = new ContentDisposition(path);
                    filename = contentDisposition.FileName;
                }

                using (Stream responseStream = response.GetResponseStream())
                using (FileStream fileStream = File.Create(System.IO.Path.Combine(destinationDirectory, filename)))
                {
                    byte[] buffer = new byte[1024*1024]; // 1MB buffer
                    ProgressEventArgs eventArgs = new ProgressEventArgs(_totalBytesLength);

                    int size = responseStream.Read(buffer, 0, buffer.Length);
                    while (size > 0)
                    {
                        fileStream.Write(buffer, 0, size);
                        _transferredBytes += size;

                        size = responseStream.Read(buffer, 0, buffer.Length);

                        eventArgs.UpdateData(_transferredBytes, _transferredPercents);
                        OnDownloadProgressChanged(eventArgs);
                    }
                }
            }

            downloadedFilePath = Path.Combine(destinationDirectory, filename);
            OnDownloadFileCompleted(EventArgs.Empty);
        }
        catch (Exception e)
        {
            OnError($"{e.Message} => {e?.InnerException?.Message}");
        }
    }

    //events
    public event EventHandler<ProgressEventArgs> DownloadProgressChanged;
    public event EventHandler DownloadFileCompleted;
    public event EventHandler<string> Error;

    public class ProgressEventArgs : EventArgs
    {
        public long TransferredBytes { get; set; }
        public int TransferredPercents { get; set; }
        public long TotalBytesLength { get; set; }

        public ProgressEventArgs(long transferredBytes, int transferredPercents, long totalBytesLength)
        {
            TransferredBytes = transferredBytes;
            TransferredPercents = transferredPercents;
            TotalBytesLength = totalBytesLength;
        }

        public ProgressEventArgs(long totalBytesLength)
        {
            this.TotalBytesLength = totalBytesLength;
        }

        public void UpdateData(long transferredBytes, int transferredPercents)
        {
            TransferredBytes = transferredBytes;
            TransferredPercents = transferredPercents;
        }
    }

    protected virtual void OnDownloadProgressChanged(ProgressEventArgs e)
    {
        DownloadProgressChanged?.Invoke(this, e);
    }
    protected virtual void OnDownloadFileCompleted(EventArgs e)
    {
        DownloadFileCompleted?.Invoke(this, e);
    }
    protected virtual void OnError(string errorMessage)
    {
        Error?.Invoke(this, errorMessage);
    }

}

这是一个测试示例:

static void Main(string[] args)
{
    HttpWebRequestDownload hDownload = new HttpWebRequestDownload();

    string downloadUrl = "http://speedtest.tele2.net/10MB.zip";
    hDownload.DownloadProgressChanged += HDownloadOnDownloadProgressChanged;
    hDownload.DownloadFileCompleted += delegate(object o, EventArgs args)
    {
        Debug.WriteLine("Download finished and saved to: "+hDownload.downloadedFilePath); 
    };
    hDownload.Error += delegate(object o, string errMessage) { Debug.WriteLine("Error has occured !! => "+errMessage); };
    hDownload.DownloadFile(downloadUrl);
}


private void HDownloadOnDownloadProgressChanged(object sender, HttpWebRequestDownload.ProgressEventArgs e)
{
    Debug.WriteLine("progress: "+e.TransferredBytes+" => "+e.TransferredPercents);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接