Downloading File With Progress

As I was creating upgrade procedure for few programs of mine I had a need to download file. With progress bar. Most of you can already see a solution: HttpWebRequest in BackgroundWorker.

Base idea is creation of HttpWebRequest, getting it's response as stream and iterating through all bytes until we read them all. Heart of (DoWork) code is:

var request = (HttpWebRequest)HttpWebRequest.Create(url);
using (var response = (HttpWebResponse)request.GetResponse()) {
using (var stream = response.GetResponseStream()) {
using (var bytes = new MemoryStream()) {
var buffer = new byte[256];
while (bytes.Length < response.ContentLength) {
var read = stream.Read(buffer, 0, buffer.Length);
if (read > 0) {
bytes.Write(buffer, 0, read);
bcwDownload.ReportProgress((int)(bytes.Length * 100 / len));
} else {
break;
}
}
}
}
}

Before we send result back to RunWorkerCompleted event we need to get file name that was actually delivered. While this step is optional, I find it especially useful if there are some redirections on web site (e.g. pointing you to newer version of file):

string fileName = response.ResponseUri.Segments[response.ResponseUri.Segments.Length - 1];
e.Result = new DownloadResult(fileName, bytes.ToArray());

P.S. Do notice that DownloadResult is our own class - there is no such class in .NET Framework.

In RunWorkerCompleted we only must save file as such:

var res = (DownloadResult)e.Result;
var file = new FileInfo(res.FileName);
using (var frm = new SaveFileDialog() { FileName = file.Name }) {
if (frm.ShowDialog(this) == DialogResult.OK) {
File.WriteAllBytes(frm.FileName, res.Bytes);
MessageBox.Show(this, "Done.", "Something", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}

And with that you have your file downloaded.

Full source code (with all missing parts of code) is available for download.

Leave a Reply

Your email address will not be published. Required fields are marked *