Home > Back-end >  How can I calculate and display download speed using webclient?
How can I calculate and display download speed using webclient?

Time:10-12

The goal is to calculate and display on label4.Text the download speed while downloading.

private void Download()
        {
            using (var client = new WebClient())
            {
                client.DownloadFileCompleted  = (s, e) => label1.Text = "Download file completed.";
                client.DownloadProgressChanged  = (s, e) => progressBar1.Value = e.ProgressPercentage;
                client.DownloadProgressChanged  = (s, e) => label2.Text = FormatBytes(e.BytesReceived);
                client.DownloadProgressChanged  = (s, e) => label4.Text = e.
                client.DownloadProgressChanged  = (s, e) =>
                {
                    label3.Text = "%"   e.ProgressPercentage.ToString();
                    label3.Left = Math.Min(
                        (int)(progressBar1.Left   e.ProgressPercentage / 100f * progressBar1.Width),
                        progressBar1.Width - label3.Width
                    );                   
                };

                client.DownloadFileAsync(new Uri("https://speed.hetzner.de/10GB.bin"), @"d:\10GB.bin");
            }
        } 

At the line with the label4.Text I want to display the speed.

client.DownloadProgressChanged  = (s, e) => label4.Text = e.

CodePudding user response:

As @AKX suggested, Stopwatch class help you to calculate bytes per second receive while downloading file.

Create a field in class scope (example based on WPF Application):

public partial class MainWindow : Window 
{
    private readonly System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
}

When initializing WebClient (as simplest way), create 2 handlers: for WebClient.DownloadProgressChanged event and for WebClient.DownloadFileCompleted event. Then before you call WebClient.DownloadFileAsync() call stopwatch.Start() to begin measuring time.

using (System.Net.WebClient wc = new System.Net.WebClient())
{
    wc.DownloadProgressChanged  = OnDownloadProgressChange;
    wc.DownloadFileCompleted  = OnDownloadFileComplete;

    stopwatch.Start(); // Start the Stopwatch
    wc.DownloadFileAsync(downloadLink, fileName); // Run file download asynchroniously
}

In DownloadProgressChanged event handler you can combine DownloadProgressChangedEventArgs's BytesReceived property and Stopwatch's Elapsed.TotalSeconds property to get download speed:

private void OnDownloadProgressChange(object sender, System.Net.DownloadProgressChangedEventArgs e)
{
    // Calculate progress values
    string downloadSpeed = string.Format("{0} MB/s", (e.BytesReceived / 1024.0 / 1024.0 / stopwatch.Elapsed.TotalSeconds).ToString("0.00"));
}

I divide BytesReceived twice by 1024 to get value in MB instead of Bytes, but you can choose as you wish. Also I format result value to 0.00 (to get "1.23 MB/s" for example). You can also calculate and format other DownloadProgressChangedEventArgs properties for you purposes if needed.

And finally, at WebClient.DownloadFileCompleted event handler you should reset the Stopwatch to stop it and reset its measured time for other new downloads:

private void OnDownloadFileComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
    stopwatch.Reset();
}

Complete version may look like this (MainWindow.cs):

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private readonly System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();

    private void BtnDownloadFile_Click(object sender, RoutedEventArgs e)
    {
        Uri downloadLink = new Uri("https://speed.hetzner.de/100MB.bin");
        string fileName = "H:\\100MB.bin";

        btnDownloadFile.IsEnabled = false; // Disable to prevent multiple runs

        using (System.Net.WebClient wc = new System.Net.WebClient())
        {
            wc.DownloadProgressChanged  = OnDownloadProgressChange;
            wc.DownloadFileCompleted  = OnDownloadFileComplete;

            stopwatch.Start();
            wc.DownloadFileAsync(downloadLink, fileName);
        }
    }

    private void OnDownloadProgressChange(object sender, System.Net.DownloadProgressChangedEventArgs e)
    {
        // Calculate progress values
        string downloadProgress = e.ProgressPercentage   "%";
        string downloadSpeed = string.Format("{0} MB/s", (e.BytesReceived / 1024.0 / 1024.0 / stopwatch.Elapsed.TotalSeconds).ToString("0.00"));
        string downloadedMBs = Math.Round(e.BytesReceived / 1024.0 / 1024.0)   " MB";
        string totalMBs = Math.Round(e.TotalBytesToReceive / 1024.0 / 1024.0)   " MB";

        // Format progress string
        string progress = $"{downloadedMBs}/{totalMBs} ({downloadProgress}) @ {downloadSpeed}"; // 10 MB / 100 MB (10%) @ 1.23 MB/s

        // Set values to contols
        lblProgress.Content = progress;
        progBar.Value = e.ProgressPercentage;
    }

    private void OnDownloadFileComplete(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
    {
        lblProgress.Content = "Download complete!";
        stopwatch.Reset();
        btnDownloadFile.IsEnabled = true; // Restore arailability of download button
    }
}

XAML:

<Grid>
    <StackPanel HorizontalAlignment="Stretch" 
                VerticalAlignment="Center">
        <Label x:Name="lblProgress" 
               Content="Here would be progress text" 
               Margin="10,0,10,5" 
               HorizontalContentAlignment="Center"/>
        <ProgressBar x:Name="progBar" 
                     Height="20" 
                     Margin="10,0,10,5" />
        <Button x:Name="btnDownloadFile" 
                Content="Download file" 
                Width="175" 
                Height="32" 
                Click="BtnDownloadFile_Click"/>
    </StackPanel>
</Grid>

How it would look:

enter image description here

  • Related