How to Download a File from Internet in C#

By FoxLearn 11/27/2024 8:40:43 AM   14.74K
Downloading a file from the internet in C# can be done using the HttpClient class or the WebClient class.

In a Windows Forms application, file downloads can be enhanced by adding progress updates and keeping the UI responsive. This guide demonstrates how to create a file downloader using WebClient, featuring a progress bar and multithreaded execution.

How to Download a File from Internet in C#?

Open Visual Studio, then click New Project, then select Visual C# on the left, then Windows and then select Windows Forms Application. Name your project "DownloadDemo" and then click OK

Drag and drop the Label, Button, TextBox, ProgressBar controls from the Visual Toolbox onto your form designer, then design your form as shown below.

download file in c#

For example, Using WebClient

The WebClient class is older and part of the System.Net namespace. It’s simple to use but is considered outdated for new projects.

In the Form1_Load event, initialize the WebClient and attach event handlers for progress updates and completion notifications:

private void Form1_Load(object sender, EventArgs e)
{
    client = new WebClient();
    client.DownloadProgressChanged += Client_DownloadProgressChanged;
    client.DownloadFileCompleted += Client_DownloadFileCompleted;
}

The btnDownload_Click event starts the download on a separate thread, ensuring the UI remains responsive:

private void btnDownload_Click(object sender, EventArgs e)
{
    //Run download file with multiple thread
    string url = txtUrl.Text;
    if (!string.IsNullOrEmpty(url))
    {
        Thread thread = new Thread(() =>
        {
            Uri uri = new Uri(url);
            string fileName = System.IO.Path.GetFileName(uri.AbsolutePath);
            client.DownloadFileAsync(uri, Application.StartupPath + "/" + fileName);
        });
        thread.Start();
    }
}

The DownloadProgressChanged event updates the progress bar and label dynamically.

private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    //Update progress bar & label
    Invoke(new MethodInvoker(delegate ()
    {
        progressBar.Minimum = 0;
        double receive = double.Parse(e.BytesReceived.ToString());
        double total = double.Parse(e.TotalBytesToReceive.ToString());
        double percentage = receive / total * 100;
        lblStatus.Text = $"Downloaded {string.Format("{0:0.##}", percentage)}%";
        progressBar.Value = int.Parse(Math.Truncate(percentage).ToString());
    }));
}

When the download is complete, the DownloadFileCompleted event shows a message box.

private void Client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
    MessageBox.Show("Download complete !", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

Below is the form code.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DownloadDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        WebClient client;     
    }
}

For example, Using HttpClient

The HttpClient class is part of the System.Net.Http namespace and is more modern and flexible way to perform asynchronous tasks, including downloading files with progress updates.

HttpClient client;

private void Form1_Load(object sender, EventArgs e)
{
    // Initialize HttpClient
    client = new HttpClient();
}

We use HttpClient.GetAsync() to start downloading the file, and HttpCompletionOption.ResponseHeadersRead to ensure that the headers are read immediately, allowing us to start downloading the content as soon as possible.

The btnDownload_Click method now uses async/await to download the file asynchronously, which keeps the UI responsive during the download.

private async void btnDownload_Click(object sender, EventArgs e)
{
    // Run download file with multiple thread
    string url = txtUrl.Text;
    if (!string.IsNullOrEmpty(url))
    {
        Uri uri = new Uri(url);
        string fileName = Path.GetFileName(uri.AbsolutePath);
        string destinationPath = Path.Combine(Application.StartupPath, fileName);

        // Start the download process in a separate task
        await DownloadFileAsync(uri, destinationPath);
    }
}

The DownloadFileAsync method is responsible for reading the file stream, writing it to disk, and reporting progress.

private async Task DownloadFileAsync(Uri uri, string destinationPath)
{
    try
    {
        // Start the download process asynchronously
        var response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);

        // Ensure the request was successful
        response.EnsureSuccessStatusCode();

        var totalBytes = response.Content.Headers.ContentLength ?? 0;
        var progress = new Progress<double>(value =>
        {
            // Update progress bar & label
            Invoke(new MethodInvoker(delegate ()
            {
                progressBar.Minimum = 0;
                double percentage = value * 100;
                lblStatus.Text = $"Downloaded {string.Format("{0:0.##}", percentage)}%";
                progressBar.Value = (int)Math.Truncate(percentage);
            }));
        });

        using (var stream = await response.Content.ReadAsStreamAsync())
        {
            using (var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                var buffer = new byte[8192];
                long totalRead = 0;
                int bytesRead;

                while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                {
                    await fileStream.WriteAsync(buffer, 0, bytesRead);

                    totalRead += bytesRead;
                    var progressPercentage = (double)totalRead / totalBytes;
                    progress.Report(progressPercentage);
                }
            }
        }

        MessageBox.Show("Download complete!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

We use a Progress<double> instance to report the download progress. The progress percentage is calculated based on the total file size (ContentLength) and the number of bytes read (totalRead).

The file is saved to the disk using a FileStream. The data is written in small chunks (buffer size of 8KB) for efficient memory usage.

VIDEO TUTORIAL