Reply to comment

C# Download File with Progress Bar

The following is a snippet of code to download a file in a Windows Forms application using C# and the System.Net.WebClient object. This code also updates a progress bar as the file is downloaded.

First, create a new windows forms application with C# as the target language. (NOTE: This works in any .NET framework version). Add a ProgressBar to the form and a BackgroundWorker control. Also add a Button to the form. The form will look something like this:

windows form application



We need some kind of background thread to update the progress bar while the file is downloaded. If we tried to update the progress bar from the main thread, out app will just hang, allowing no user input, and the progress bar would not change until the file was completely downloaded. Instead, we need to let the main thread run separately from our lengthy download operation. Set the BackgroundWorker's properties like this:

backgroundworker properties

Go to the Events view of the BackgroundWorker and double click each of its events so they are auto-wired up as shown here:

backgroundworker events

Double click the button to auto-wire up the event click event and call our background worker to start running asynchronously when the button is clicked. Your code will look something like this:

private void btnTestDownload_Click(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync();
}

In the BackgroundWorker's DoWork method, we put the code to run the download on a separate thread. The code will look something like this:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    // the URL to download the file from
    string sUrlToReadFileFrom = "http://devtoolshed.googlepages.com/filezilla_download.exe";
    // the path to write the file to
    string sFilePathToWriteFileTo = "C:\\filezilla_download.exe";
 
    // first, we need to get the exact size (in bytes) of the file we are downloading
    Uri url = new Uri(sUrlToReadFileFrom);
    System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
    System.Net.HttpWebResponse response = (System.Net.HttpWebResponse)request.GetResponse();
    response.Close();
    // gets the size of the file in bytes
    Int64 iSize = response.ContentLength;
 
    // keeps track of the total bytes downloaded so we can update the progress bar
    Int64 iRunningByteTotal = 0;
 
    // use the webclient object to download the file
    using (System.Net.WebClient client = new System.Net.WebClient())
    {
        // open the file at the remote URL for reading
        using (System.IO.Stream streamRemote = client.OpenRead(new Uri(sUrlToReadFileFrom)))
        {
            // using the FileStream object, we can write the downloaded bytes to the file system
            using (Stream streamLocal = new FileStream(sFilePathToWriteFileTo, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                // loop the stream and get the file into the byte buffer
                int iByteSize = 0;
                byte[] byteBuffer = new byte[iSize];
                while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
                {
                    // write the bytes to the file system at the file path specified
                    streamLocal.Write(byteBuffer, 0, iByteSize);
                    iRunningByteTotal += iByteSize;
 
                    // calculate the progress out of a base "100"
                    double dIndex = (double)(iRunningByteTotal);
                    double dTotal = (double)byteBuffer.Length;
                    double dProgressPercentage = (dIndex / dTotal);
                    int iProgressPercentage = (int)(dProgressPercentage * 100);
 
                    // update the progress bar
                    backgroundWorker1.ReportProgress(iProgressPercentage);
                }
 
                // clean up the file stream
                streamLocal.Close();
            }
 
            // close the connection to the remote server
            streamRemote.Close();
        }
    }
}

Now implement the BackgroundWorker's ProgressChanged event to update the progress bar. NOTE: You can ONLY update the progress bar in this method. This method synchronized back with the form's main thread. If you tried to update the progress bar from the DoWork method, you would get an exception because that is not on the same thread as the form. Here's the code:

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}

For convenience, in the result you can show a message that your file is downloaded to note that it is completely finished like this:

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    MessageBox.Show("File download complete");
}

Reply