Scott
Scott

Reputation: 6251

Measuring download speed

I'm downloading a file using the following:

Dim client As WebClient = New WebClient()
client.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), "C:\Users\Dir\100mb.test")

The file downloads and saves into the C://Users/Dir/100mb.test, but while its downloading I would like to display the download speed in a label. How can I do this? I have read many tutorials, but most of them doesn't works or are outdated. I'm a newbie with vb.net, so I can't really write something on my own, could you give me any solutions?

Upvotes: 0

Views: 5826

Answers (4)

Niels Koomans
Niels Koomans

Reputation: 1

Try this:

Try this only when you're downloading through a backgroundworker

Private Sub worker_DoWork(Byval sender As Object, Byval e As DoWorkEventArgs)

Dim req As WebRequest = WebRequest.Create(downloadUrl) 'Make a request for the url of the file to be downloaded
Dim resp As WebResponse = req.GetResponse 'Ask for the response
Dim fs As New FileStream(path to download to, FileMode.CreateNew) 'Create a new FileStream that writes to the desired download path

Dim buffer(8192) As Byte 'Make a buffer
Dim downloadedsize As Long = 0
Dim downloadedTime As Long = 0

Dim dlSpeed As Long = 0
Dim currentSize As Long = 0 'Size that has been downloaded
Dim totalSize As Long = req.ContentLength 'Total size of the file that has to be downloaded

  Do While currentSize < totalSize
   Dim read As Integer = resp.GetResponseStream.Read(buffer, 0, 8192) 'Read the buffer from the response the WebRequest gave you

   fs.Write(buffer, 0, read) 'Write to filestream that you declared at the beginning of the DoWork sub

   currentSize += read

   downloadedSize += read
   downloadedTime += 1 'Add 1 millisecond for every cycle the While field makes

   If downloadedTime = 1000 Then 'Then, if downloadedTime reaches 1000 then it will call this part
      dlSpeed = (downloadedSize / TimeSpan.FromMilliseconds(downloadedTime).TotalSeconds) 'Calculate the download speed by dividing the downloadedSize by the total formatted seconds of the downloadedTime

      downloadedTime = 0 'Reset downloadedTime and downloadedSize
      downloadedSize = 0
   End If
  End While

fs.Close() 'Close the FileStream first, or the FileStream will crash.
resp.Close() 'Close the response

End Sub

Sorry for not using proper formatting, but this is a solution in itself.

Upvotes: 0

Danpe
Danpe

Reputation: 19047

Define globals:

Dim lastUpdate As DateTime
Dim lastBytes As Long = 0

You'll need to assign an Event for progress:

Dim client As WebClient = New WebClient()
client.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), "C:\Users\Dir\100mb.test")
client.DownloadProgressChanged += Function(sender, e) progressChanged(e.BytesReceived)

The Event:

Private Sub progressChanged(bytes As Long)
    If lastBytes = 0 Then
        lastUpdate = DateTime.Now
        lastBytes = bytes
        Return
    End If

    Dim now = DateTime.Now
    Dim timeSpan = now - lastUpdate
    If Not timeSpan.Seconds = 0
         Dim bytesChange = bytes - lastBytes
         Dim bytesPerSecond = bytesChange / timeSpan.Seconds

         lastBytes = bytes
         lastUpdate = now
    End If
End Sub

And you have the calculations of bytes per second.

label.Text = bytesPerSecond.ToString() + "B/s"; 

Upvotes: 0

igrimpe
igrimpe

Reputation: 1785

May I suggest something different?

Imports System.Net

Public Class Form1

Private tmp = IO.Path.Combine(My.Computer.FileSystem.SpecialDirectories.Temp, "snafu.fubar")
Private Downloading As Boolean = False

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    If Downloading Then Exit Sub
    Downloading = True

    Dim wc As New WebClient
    AddHandler wc.DownloadProgressChanged, AddressOf wc_ProgressChanged
    AddHandler wc.DownloadFileCompleted, AddressOf wc_DownloadDone

    wc.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), tmp, Stopwatch.StartNew)

End Sub

Private Sub wc_DownloadDone(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs)
    Downloading = False
End Sub

Private Sub wc_ProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs)
    Me.Label1.Text = (e.BytesReceived / (DirectCast(e.UserState, Stopwatch).ElapsedMilliseconds / 1000.0#)).ToString("#")
End Sub

End Class

Because it makes no sense to determine the speed by the last chunk of bytes received, but instead you measure the total number of bytes and divide by the TOTAL time. Passing a stopwatch instance to the eventhandler has the advantage that it doesnt 'spoil' your class code - it''s visible only where it's needed.

Upvotes: 1

Ric
Ric

Reputation: 13248

This will give you percentage in the mean time. You could probably calculate from the percentage given a start time using DateTime.Now the speed in which it the download is taking:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Try

    Dim client As WebClient = New WebClient()
    AddHandler client.DownloadProgressChanged, AddressOf ProgChanged
    client.DownloadFileAsync(New Uri("http://cachefly.cachefly.net/100mb.test"), "C:\Users\Dir\100mb.test")

Catch ex As Exception
    MessageBox.Show(ex.Message)
End Try
End Sub

Private Sub ProgChanged(ByVal sender As Object, ByVal e As DownloadProgressChangedEventArgs)
        Dim progressPercentage As Integer = e.ProgressPercentage
End Sub

Upvotes: 0

Related Questions