How To Use HttpWebRequest/Response To Download A Binary (.exe) File From A Web Server?

感情迁移 提交于 2021-01-26 03:43:21

问题


I am writing a program that needs to download an .exe file from a website and then save it to the hard drive. The .exe is stored on my site and it's url is as follows (it's not the real uri just one I made up for the purpose of this question):

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

After many web searches and fumbling through examples here is the code I have come up with so far:

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();

As you can see I am using the StreamReader class to read the data. After calling ReadToEnd does the stream reader contain the (binary) content of my .exe? Can I just write the content of the StreamReader to a file (named calc.exe) and I will have succesfully downloaded the .exe?

I am wondering why StreamReader ReadToEnd returns a string. In my case would this string be the binary content of calc.exe?


回答1:


WebClient is the best method to download file. But you can use the following method to download a file asynchronously from web server.

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)
    {
    }
}

There is a similar thread here - how to download the file using httpwebrequest




回答2:


StreamReader is a text reader implementation i.e. it should be used to read text data and not binary data. In your case, you should be directly using the underlying response stream.

For downloading file, the simplest way would be to use WebClient.DownloadFile method.




回答3:


This should directly save the file on your hard disk.

using System.Net;
using (WebClient webClient = new WebClient ())
{
    webClient.DownloadFile("http://www.mysite.com/calc.exe", "calc.exe");
}



回答4:


Instead of using StreamReader, you should really call Read() method of your Stream object. That will ask you for a byte[] buffer to be fill with read data, which you can then write to disk using StreamWriter or FileStream.




回答5:


I'm probably a little bit late but I had the same problem with files being always 0kb big if not running in Debug mode.. This might be a relatively simple answer but disabling "DEBUG-Constants" under Properties solved it for me.




回答6:


I have created a class with events so you can track download progress:

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

}

Here is testing example:

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


来源:https://stackoverflow.com/questions/14192993/how-to-use-httpwebrequest-response-to-download-a-binary-exe-file-from-a-web-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!