Save/Load BackgroundWorker Progress in vb.net - vb.net

I am creating a file downloader using backgroundworker & i want to save the progress of backgroundworker so that when i restart the application, on resume, it start the download where i closed last time.
Any help ?
Here is My code for Downloader
Public Class cls_FileDownloader
Dim FileSave As String
Delegate Sub DownloadFIlesafe(ByVal Cancelled As Boolean)
Delegate Sub ChangeTextsSafe(ByVal length As Long, ByVal position As Double, ByVal percent As Long, ByVal speed As Long)
Private Sub cls_FileDownloader_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Label1.Text = ""
btn_Cancel.Enabled = False
End Sub
Private Sub btn_Download_Click(sender As Object, e As EventArgs) Handles btn_Download.Click
If Me.txt_Url.Text <> "" Then
Me.SaveFile.FileName = txt_Url.Text.Split("\"c)(txt_Url.Text.Split("\"c).Length - 1)
If SaveFile.ShowDialog = System.Windows.Forms.DialogResult.OK Then
FileSave = SaveFile.FileName
SaveFile.FileName = ""
lbl_SaveTO.Text = "Save To:" & FileSave
txt_Url.Enabled = False
btn_Download.Enabled = False
btn_Cancel.Enabled = True
bg_Worker.RunWorkerAsync()
End If
Else
MessageBox.Show("Please Insert valid file path", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
End Sub
Private Sub bg_Worker_DoWork(sender As Object, e As DoWorkEventArgs) Handles bg_Worker.DoWork
Dim response As FileWebResponse
Dim request As FileWebRequest
Try
request = WebRequest.Create(txt_Url.Text)
response = request.GetResponse
Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Dim cancelDelegate As New DownloadFIlesafe(AddressOf Download_Complete)
Me.Invoke(cancelDelegate, True)
Exit Sub
End Try
Dim length As Long = response.ContentLength
Dim safedelegate As New ChangeTextsSafe(AddressOf ChangeTexts)
Me.Invoke(safedelegate, length, 0, 0, 0)
Dim writeStream As New IO.FileStream(Me.FileSave, IO.FileMode.Create)
Dim nRead As Double
'To calculate the download speed
Dim speedtimer As New Stopwatch
Dim currentspeed As Long = -1
Dim readings As Integer = 0
Do
If bg_Worker.CancellationPending Then 'If user abort download
Exit Do
End If
speedtimer.Start()
Dim readBytes(4095) As Byte
Dim bytesread As Long = response.GetResponseStream.Read(readBytes, 0, 4096)
nRead += bytesread
Dim percent As Long = (nRead * 100) / length
Me.Invoke(safedelegate, length, nRead, percent, currentspeed)
If bytesread = 0 Then Exit Do
writeStream.Write(readBytes, 0, bytesread)
speedtimer.Stop()
readings += 1
If readings >= 5 Then 'For increase precision, the speed it's calculated only every five cicles
currentspeed = 20480 / (speedtimer.ElapsedMilliseconds / 1000)
speedtimer.Reset()
readings = 0
End If
Loop
'Close the streams
response.GetResponseStream.Close()
writeStream.Close()
If Me.bg_Worker.CancellationPending Then
IO.File.Delete(Me.FileSave)
Dim cancelDelegate As New DownloadFIlesafe(AddressOf Download_Complete)
Me.Invoke(cancelDelegate, True)
Exit Sub
End If
Dim completeDelegate As New DownloadFIlesafe(AddressOf Download_Complete)
Me.Invoke(completeDelegate, False)
End Sub

Related

tcpclient webrelay and control analog outputs

This is the first time that I have ever worked with networking in a program control webrelay. I was able to write my program with success... or so I thought. A couple of days ago I had a device drop off the network and my program "locked up". I know it did not truly lock up. I did some debugging and found out that what is happening is that when the tcpclient throws an exception, it just stops running any code after it. This causes my program to stop updating because of a timer that is never restarted and I con't control analog Outputs.
Public Class ControlPanelX317
Private SQL As New SQLControl
Private Sub ControlPanelX317_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LoadControlsX317()
End Sub
'Dislay Conrol
'__________________________________________________________________________________________________________________________________________________________________________
Private Sub LoadControlsX317()
Dim loadqry As String = "SELECT * FROM controlsX317 WHERE controlsX317.ValueVoltageID = '" & 1 & "' "
Dim SQLCmd As New SqlCommand(loadqry, Sql.SQLCon)
If Sql.SQLCon.State = ConnectionState.Closed Then Sql.SQLCon.Open()
Dim reader As SqlDataReader = SQLCmd.ExecuteReader
While reader.Read = True
txt_S1_VolueVoltage.Text = reader("S1VolueVoltage")
txt_S2_VolueVoltage.Text = reader("S2VolueVoltage")
txt_S3_VolueVoltage.Text = reader("S3VolueVoltage")
txt_S4_VolueVoltage.Text = reader("S4VolueVoltage")
End While
SQLCmd.Dispose()
reader.Close()
Sql.SQLCon.Close()
End Sub
Private Sub btn_Save_ValueVoltage_Click(sender As Object, e As EventArgs) Handles btn_Save_ValueVoltage.Click
If txt_S1_VolueVoltage.Text > 10 Then
MsgBox("Max Voltage is 10V")
txt_S1_VolueVoltage.Clear()
Exit Sub
End If
If txt_S2_VolueVoltage.Text > 10 Then
MsgBox("Max Voltage is 10V")
txt_S2_VolueVoltage.Clear()
Exit Sub
End If
If txt_S3_VolueVoltage.Text > 10 Then
MsgBox("Max Voltage is 10V")
txt_S3_VolueVoltage.Clear()
Exit Sub
End If
If txt_S4_VolueVoltage.Text > 10 Then
MsgBox("Max Voltage is 10V")
txt_S4_VolueVoltage.Clear()
Exit Sub
End If
If txt_S1_VolueVoltage.Text <> "" Then
Dim UpdateValueVoltage As String = "UPDATE controlsX317 SET S1VolueVoltage='" & txt_S1_VolueVoltage.Text & "', S2VolueVoltage='" & txt_S2_VolueVoltage.Text & "',
S3VolueVoltage='" & txt_S3_VolueVoltage.Text & "', S4VolueVoltage='" & txt_S4_VolueVoltage.Text & "'
WHERE ValueVoltageID ='" & 1 & "' "
If SQL.DataUpdate(UpdateValueVoltage) = 0 Then
MsgBox("The Sysytem could not be found!!! ")
Else
MsgBox("VolueVoltage successfully changed")
End If
Else
MsgBox("You must restart a Sysytem")
End If
End Sub
Private Sub btn_S1_SetVoltage_Click(sender As Object, e As EventArgs) Handles btn_S1_SetVoltage.Click
lbl_S1_AnalogOutput.Text = Val(txt_S1_VolueVoltage.Text) * Val(txt_S1_ControlViltage.Text / 100) & "V"
End Sub
Private Sub btn_S2_SetVoltage_Click(sender As Object, e As EventArgs) Handles btn_S2_SetVoltage.Click
lbl_S2_AnalogOutput.Text = Val(txt_S2_VolueVoltage.Text) * Val(txt_S2_ControlViltage.Text / 100) & "V"
End Sub
Private Sub btn_S3_SetVoltage_Click(sender As Object, e As EventArgs) Handles btn_S3_SetVoltage.Click
lbl_S3_AnalogOutput.Text = Val(txt_S3_VolueVoltage.Text) * Val(txt_S3_ControlViltage.Text / 100) & "V"
End Sub
Private Sub btn_S4_SetVoltage_Click(sender As Object, e As EventArgs) Handles btn_S4_SetVoltage.Click
lbl_S4_AnalogOutput.Text = Val(txt_S4_VolueVoltage.Text) * Val(txt_S4_ControlViltage.Text / 100) & "V"
End Sub
'End Display Control
'_________________________________________________________________________________________________________________________________________________________________________
'Conection to WebRelay X317
'_________________________________________________________________________________________________________________________________________________________________________
Public Sub getWebRelayState()
Dim tcpClient As New TcpClient()
Dim port As Integer
Try
port = Convert.ToInt32(txtPort.Text)
tcpClient.Connect(txt_IPAddress.Text, port)
If tcpClient.Connected Then
'Create a network stream object
Dim netStream As NetworkStream = tcpClient.GetStream()
'If we can read and write to the stream then do so
If netStream.CanWrite And netStream.CanRead Then
'Send the on command to webrelay
Dim sendBytes As Byte() = Encoding.ASCII.GetBytes("GET /state.xml?noReply=0 HTTP/1.1" & vbCrLf & "Authorization: Basic bm9uZTp3ZWJyZWxheQ==" & vbCrLf & vbCrLf)
netStream.Write(sendBytes, 0, sendBytes.Length)
'Get the response from webrelay
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
netStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
'Parse the response and update the webrelay state and input text boxes
Dim returndata As String = Encoding.ASCII.GetString(bytes)
'Parse out the relay state and input state
Dim array1 As Char() = returndata.ToCharArray()
Dim ana(4) As Integer
'Relay State found at index 66
If array1(66) = "1" Then
RelayState.Text = "ON"
Else
RelayState.Text = "OFF"
End If
'Input State found at index 94
If array1(94) = "1" Then
inputState.Text = "ON"
Else
inputState.Text = "OFF"
End If
End If
'Close the connection
tcpClient.Close()
End If
Catch ex As Exception
inputState.Text = "Error"
RelayState.Text = "Error"
'Disable the timer
TimerRelayRefresh.Enabled = False
End Try
End Sub
Private Sub sendRequest(ByVal val As String)
Dim tcpClient As New TcpClient()
Dim port As Integer
Try
'Disable the timer
TimerRelayRefresh.Enabled = False
port = Convert.ToInt32(txtPort.Text)
tcpClient.Connect(txt_IPAddress.Text, port)
If tcpClient.Connected Then
MsgBox("connection successful")
'Create a network stream object
Dim netStream As NetworkStream = tcpClient.GetStream()
'If we can read and write to the stream then do so
If netStream.CanWrite And netStream.CanRead Then
'Send the on command to webrelay
Dim sendBytes As Byte() = Encoding.ASCII.GetBytes("GET /state.xml?relayState=1 HTTP/1.1<CR><LF>" & vbCrLf & "Authorization: Basic bm9uZTp3ZWJyZWxheQ==<CR><LF><CR><LF>" & vbCrLf & vbCrLf)
netStream.Write(sendBytes, 0, sendBytes.Length)
'Get the response from webrelay
Dim bytes(tcpClient.ReceiveBufferSize) As Byte
netStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
'Parse the response and update the webrelay state and input text boxes
Dim returndata As String = Encoding.ASCII.GetString(bytes)
'Parse out the relay state and input state
Dim array1 As Char() = returndata.ToCharArray()
'Relay State found at index 66
If array1(66) = "1" Then
RelayState.Text = "ON"
Else
RelayState.Text = "OFF"
End If
'Input State found at index 94
If array1(94) = "1" Then
inputState.Text = "ON"
End If
Else
inputState.Text = "OFF"
End If
End If
'Enable the timer
TimerRelayRefresh.Enabled = True
Catch ex As Exception
inputState.Text = "Error"
RelayState.Text = "Error"
'Disable the timer
TimerRelayRefresh.Enabled = False
End Try
End Sub
Private Sub btn_ControlsX317_On_Click(sender As Object, e As EventArgs) Handles btn_ControlsX317_On.Click
sendRequest("1")
End Sub
Private Sub btn_ControlsX317_Off_Click(sender As Object, e As EventArgs) Handles btn_ControlsX317_Off.Click
sendRequest("0")
End Sub
Private Sub btn_ControlsX317_PULSE_Click(sender As Object, e As EventArgs) Handles btn_ControlsX317_PULSE.Click
sendRequest("2")
End Sub
'End Conetion
'_________________________________________________________________________________________________________________________________________________________________________
End Class

FOR statement conflicting with IF statement in VB

I am creating a fairly simple ping tool which shows in milliseconds how long the server took to respond. If the server does not respond, it shows as it responded in 0ms. I wanted to implement an If statement to write Server failed to respond in the ListBox rather than it replied in 0ms. The only problem with this is I have a chunk of code which need to be run outside the If but continues inside the If and involves using the line of code Next... This seems to cause the If statement to not recognise the End If and the End If to not recognise the If...
Here is my code:
For i As Integer = 0 To numberOfPings - 1
Dim ping As New Ping
Dim pingRe As PingReply = ping.Send(pingTarget)
If pingRe.RoundtripTime = 0 Then
Me.listboxPing.Items.Add("Server failed to respond...")
Else
Me.listboxPing.Items.Add("Response from " & pingTarget & " in " & pingRe.RoundtripTime.ToString() & "ms")
listboxPing.SelectedIndex = listboxPing.Items.Count - 1
listboxPing.SelectedIndex = -1
Application.DoEvents()
Threading.Thread.Sleep(500)
Next
Me.listboxPing.Items.Add("")
End If
Does anyone know of a way I could fix this/get around this issue?
Thanks,
If I were going to write code to ping an address and show the results it would look something like this.
Dim pingThrd As Threading.Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If pingThrd Is Nothing OrElse pingThrd.ThreadState = Threading.ThreadState.Stopped Then
RichTextBox1.Clear()
pingThrd = New Threading.Thread(AddressOf PingIt)
pingThrd.IsBackground = True
pingThrd.Start("192.168.33.1")
End If
End Sub
Public Sub PingIt(pingTarget As Object)
Dim numberOfPings As Integer = 5
Dim pingT As String = DirectCast(pingTarget, String)
Dim pingTimeOut As Integer = 1000
Const dlyBetweenPing As Integer = 500
Dim dspStr As String
For i As Integer = 0 To numberOfPings - 1
Dim pingit As New Ping
Dim pingRe As PingReply = pingit.Send(pingT, pingTimeOut)
'check if success
If pingRe.Status = IPStatus.Success Then
dspStr = String.Format("Response from: {0} in {1}ms.", pingRe.Address, pingRe.RoundtripTime)
Else
dspStr = String.Format("{0} failed. Status: {1}", pingRe.Address, pingRe.Status)
End If
Me.BeginInvoke(Sub()
RichTextBox1.AppendText(dspStr)
RichTextBox1.AppendText(Environment.NewLine)
End Sub)
Threading.Thread.Sleep(dlyBetweenPing)
Next
End Sub
edit: Same basic code but allow thread to start with different address and count.
Structure PingWhat
Dim addr As String
Dim howmany As Integer
End Structure
Dim pingThrd As Threading.Thread
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If pingThrd Is Nothing OrElse pingThrd.ThreadState = Threading.ThreadState.Stopped Then
RichTextBox1.Clear()
'setup a thread to do the actual ping'ing
'this allows the UI to function
pingThrd = New Threading.Thread(AddressOf PingIt)
pingThrd.IsBackground = True
'setup address to ping and howmany times to ping it
Dim somePing As New PingWhat With {.addr = "192.168.33.1", .howmany = 3}
'start the thread
pingThrd.Start(somePing)
End If
End Sub
Public Sub PingIt(pingTarget As Object)
Dim pingT As PingWhat = DirectCast(pingTarget, PingWhat)
Dim pingTimeOut As Integer = 1000
Const dlyBetweenPing As Integer = 500
Dim dspStr As String
For i As Integer = 1 To pingT.howmany
Dim pingit As New Ping
Dim pingRe As PingReply = pingit.Send(pingT.addr, pingTimeOut)
'check if success
If pingRe.Status = IPStatus.Success Then
dspStr = String.Format("Response from: {0} in {1} ms.", pingRe.Address, pingRe.RoundtripTime)
Else
dspStr = String.Format("Ping Failed {0}. Status: {1}", pingT.addr, pingRe.Status)
End If
'update the UI
Me.BeginInvoke(Sub()
RichTextBox1.AppendText(dspStr)
RichTextBox1.AppendText(Environment.NewLine)
RichTextBox1.ScrollToCaret()
End Sub)
Threading.Thread.Sleep(dlyBetweenPing)
Next
Me.BeginInvoke(Sub()
RichTextBox1.AppendText("Done")
RichTextBox1.AppendText(Environment.NewLine)
RichTextBox1.ScrollToCaret()
End Sub)
End Sub
Is this what you're after?
For i As Integer = 0 To numberOfPings - 1
Dim ping As New Ping
Dim pingRe As PingReply = ping.Send(pingTarget)
If pingRe.RoundtripTime = 0 Then
Me.listboxPing.Items.Add("Server failed to respond...")
Else
Me.listboxPing.Items.Add("Response from " & pingTarget & " in " & pingRe.RoundtripTime.ToString() & "ms")
listboxPing.SelectedIndex = listboxPing.Items.Count - 1
listboxPing.SelectedIndex = -1
Application.DoEvents()
Threading.Thread.Sleep(500)
add = True
Exit For
End If
Next
If add Then Me.listboxPing.Items.Add("")
The If will change the scope, therefore, you need to use a variable to check whether it went into the Else part.
Of course, you need to close the first If before the Next.
#dbasnett This was the code I using before and it was absolutely perfect for what i needed EXCEPT if a ping failed it would just say (PingTarget) responded in 0ms which is not ideal. Ideally i would like it to say Server failed to respond... . Do you know a way in which this can be achieved by modifying my original code?
Imports System.Net.NetworkInformation
Imports System.Runtime.InteropServices
Public Class PingClient
Private Const EM_SETCUEBANNER As Integer = &H1501
<DllImport("user32.dll", CharSet:=CharSet.Auto)>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As String) As Int32
End Function
Private Sub SetCueText(ByVal control As Control, ByVal text As String)
SendMessage(control.Handle, EM_SETCUEBANNER, 0, text)
End Sub
Private Sub PingClient_Load(sender As Object, e As EventArgs) Handles MyBase.Load
SetCueText(textboxIP, "IP Address/Domain")
SetCueText(textboxPing, "No. Of Pings")
End Sub
Structure PingWhat
Dim addr As String
Dim howmany As Integer
End Structure
Dim pingThrd As Threading.Thread
Public Sub buttonPing_Click(sender As Object, e As EventArgs) Handles buttonPing.Click
If pingThrd Is Nothing OrElse pingThrd.ThreadState = Threading.ThreadState.Stopped Then
Dim pingTarget As String = ""
Dim numberOfPings As Integer = 0
Dim intTimeout As Integer = 2000
If String.IsNullOrEmpty(textboxIP.Text) Then
MsgBox("You must enter an IP Address or Domain.")
Exit Sub
End If
If Not Int32.TryParse(textboxPing.Text, numberOfPings) Then
MsgBox("You must enter a number of how many times the target address will be pinged.")
Exit Sub
End If
If numberOfPings = 0 Then
MsgBox("You must enter a value over 0.")
textboxPing.Clear()
Exit Sub
End If
'setup a thread to do the actual ping'ing
'this allows the UI to function
pingThrd = New Threading.Thread(AddressOf PingIt)
pingThrd.IsBackground = True
'setup address to ping and howmany times to ping it
Dim somePing As New PingWhat With {.addr = pingTarget, .howmany = numberOfPings}
'start the thread
pingThrd.Start(somePing)
End If
Me.listboxPing.Items.Add("")
End Sub
Public Sub PingIt(pingTarget As Object)
Dim pingT As PingWhat = DirectCast(pingTarget, PingWhat)
Dim pingTimeOut As Integer = 1000
Const dlyBetweenPing As Integer = 500
Dim dspStr As String
For i As Integer = 1 To pingT.howmany
Dim pingit As New Ping
Dim pingRe As PingReply = pingit.Send(pingT.addr, pingTimeOut)
'check if success
If pingRe.Status = IPStatus.Success Then
dspStr = String.Format("Response from: {0} in {1} ms.", pingRe.Address, pingRe.RoundtripTime)
Else
dspStr = String.Format("Ping Failed {0}. Status: {1}", pingT.addr, pingRe.Status)
End If
'update the UI
Me.BeginInvoke(Sub()
listboxPing.Items.Add(dspStr)
End Sub)
Threading.Thread.Sleep(dlyBetweenPing)
Next
Me.BeginInvoke(Sub()
listboxPing.Items.Add("Done")
End Sub)
End Sub
Private Sub PingClient_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
Dim Response As Integer
Response = MsgBox("Are you sure you want to exit the Ping Tool?", 36)
If Response = MsgBoxResult.Yes Then
Else
e.Cancel = True
End If
End Sub
End Class

Whats the best download method for vb?

I am trying to make a download client with ftp and im still trying to find out whats the best i have but im in stuck because i followed a guide but it only show how much its have downloaded in bytes, how can i change it to gb? and how can i add a download speed?
Imports System.Net
Public Class MainForm
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub btnBrowseSave_Click(sender As Object, e As EventArgs) Handles btnBrowseSave.Click
Dim newFolder As New FolderBrowserDialog
If newFolder.ShowDialog = Windows.Forms.DialogResult.OK Then
txtSavePath.Text = newFolder.SelectedPath
End If
End Sub
Private Sub btnDownload_Click(sender As Object, e As EventArgs) Handles btnDownload.Click
bWorker.RunWorkerAsync()
End Sub
Private Sub bWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles bWorker.DoWork
Dim buffer(1023) As Byte
Dim bytesIn As Integer
Dim totalBytesIn As Integer
Dim output As IO.Stream
Dim flLength As Integer
Try
Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePath.Text), FtpWebRequest)
FTPRequest.Credentials = New NetworkCredential(txtFTPUsername.Text, txtFTPPassword.Text)
FTPRequest.Method = Net.WebRequestMethods.Ftp.GetFileSize
flLength = CInt(FTPRequest.GetResponse.ContentLength)
lblFileSize.Text = flLength & " bytes"
Catch ex As Exception
End Try
Try
Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePath.Text), FtpWebRequest)
FTPRequest.Credentials = New NetworkCredential(txtFTPUsername.Text, txtFTPPassword.Text)
FTPRequest.Method = WebRequestMethods.Ftp.DownloadFile
Dim stream As System.IO.Stream = FTPRequest.GetResponse.GetResponseStream
Dim OutputFilePath As String = txtSavePath.Text & "\" & IO.Path.GetFileName(txtFilePath.Text)
output = System.IO.File.Create(OutputFilePath)
bytesIn = 1
Do Until bytesIn < 1
bytesIn = stream.Read(buffer, 0, 1024)
If bytesIn > 0 Then
output.Write(buffer, 0, bytesIn)
totalBytesIn += bytesIn
lblDownloadedBytes.Text = totalBytesIn.ToString & " bytes"
If flLength > 0 Then
Dim perc As Integer = (totalBytesIn / flLength) * 100
bWorker.ReportProgress(perc)
End If
End If
Loop
output.Close()
stream.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub bWorker_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles bWorker.ProgressChanged
pBar.Value = e.ProgressPercentage
lblPercent.Text = e.ProgressPercentage.ToString & "%"
End Sub
Private Sub bWorker_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bWorker.RunWorkerCompleted
MsgBox("Download Complete!")
End Sub
End Class
1 KB = 210 bytes = 1,024 bytes
1 MB = 210 KB = 220 bytes = 1,048,576 bytes
1 GB = 210 MB = 230 bytes = 1,073,741,824 bytes
1 TB = 210 GB = 240 bytes = 1,099,511,627,776 bytes
The next units are Petabytes PB and Exabytes EB (maybe in future computer generations?).
Here is a function that formats the byte numbers. It determines the appropriate unit automatically:
Public Function FormatBytes(ByVal bytes As Long) As String
Dim sizes As String() = {"B", "KB", "MB", "GB", "TB", "PB", "EB"}
Dim order As Integer = 0
Dim len As Double = bytes
While len >= 1024 AndAlso order + 1 < sizes.Length
order += 1
len = len / 1024
End While
Return String.Format("{0:0.0} {1}", len, sizes(order))
End Function
Initialize the worker with:
bWorker.WorkerReportsProgress = True
You can also pass the number of bytes instead of a percentage to the ReportProgress method. The BackgroundWorker doesn't care. Because big files might exceed Integer.MaxValue declare totalBytesIn As Long instead as of Integer and pass the progress in KB to the ReportProgress method:
bWorker.ReportProgress(CInt(totalBytesIn / 1024))
In the ProgressChanged event handler:
Private Sub bWorker_ProgressChanged(ByVal sender As Object, _
ByVal e As ProgressChangedEventArgs) _
Handles bWorker.ProgressChanged
Me.txtProgress.Text = FormatBytes(1024 * e.ProgressPercentage)
' More code to come here ... (see below)
End Sub
As for the speed you could use a System.Diagnostics.Stopwatch. It shows you the elapsed time.
Dim stopwatch As New System.Diagnostics.Stopwatch()
stopwatch.Start()
And then in bWorker_ProgressChanged:
Dim elapsedSeconds As Double = stopwatch.ElapsedMilliseconds / 1000
If elapsedSeconds > 0 Then
Dim speed As Double = bytes / elapsedSeconds
lblSpeed.Text = FormatBytes(CInt(speed)) & " / s"
End If
The final version of the progress changed event handler:
Private Sub bWorker_ProgressChanged(ByVal sender As Object, _
ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
Handles bWorker.ProgressChanged
Dim bytes As Long = 1024 * e.ProgressPercentage
'Can exceed 100% beacause of rounding effects
Dim percent As Integer = Math.Min(100, CInt(100 * bytes \ flLength))
pBar.Value = percent
lblPercent.Text = percent & "%"
lblDownloadedBytes.Text = FormatBytes(bytes)
Dim elapsedSeconds As Double = stopwatch.ElapsedMilliseconds / 1000
If elapsedSeconds > 0 Then
Dim speed As Double = bytes / elapsedSeconds
lblSpeed.Text = FormatBytes(CInt(speed)) & " / s"
End If
End Sub
And if you declare flLength in the Form instead as local variable, you can calculate and display the percentages in bWorker_ProgressChanged as well.
As you have troubles understanding my answer, here is the complete code. Where possible I kept your code as is and marked my changes with comments ('===). (I had only my code snippets from above until now, so I had to create a form with all the required controls. It's tested and it works):
Imports System.Net
Public Class MainForm
Dim flLength As Long '=== As Form variable instead as local variable and As Long.
Dim stopwatch As New System.Diagnostics.Stopwatch() '=== New variable.
Private Sub MainForm_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Control.CheckForIllegalCrossThreadCalls = False
End Sub
Private Sub btnBrowseSave_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnBrowseSave.Click
Dim newFolder As New FolderBrowserDialog
If newFolder.ShowDialog = Windows.Forms.DialogResult.OK Then
txtSavePath.Text = newFolder.SelectedPath
End If
End Sub
Private Sub btnDownload_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnDownload.Click
bWorker.RunWorkerAsync()
End Sub
Private Sub bWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bWorker.DoWork
Dim buffer(1023) As Byte
Dim bytesIn As Integer
Dim totalBytesIn As Long '=== As Long instead of Integer
Dim output As IO.Stream
'Dim flLength As Integer '=== Now as form variable
Try
Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePath.Text), FtpWebRequest)
FTPRequest.Credentials = New NetworkCredential(txtFTPUsername.Text, txtFTPPassword.Text)
FTPRequest.Method = Net.WebRequestMethods.Ftp.GetFileSize
flLength = CInt(FTPRequest.GetResponse.ContentLength)
lblFileSize.Text = flLength & " bytes"
Catch ex As Exception
End Try
Try
stopwatch.Start() '=== Start Stopwatch
Dim FTPRequest As FtpWebRequest = DirectCast(WebRequest.Create(txtFilePath.Text), FtpWebRequest)
FTPRequest.Credentials = New NetworkCredential(txtFTPUsername.Text, txtFTPPassword.Text)
FTPRequest.Method = WebRequestMethods.Ftp.DownloadFile
Dim stream As System.IO.Stream = FTPRequest.GetResponse.GetResponseStream
Dim OutputFilePath As String = txtSavePath.Text & "\" & IO.Path.GetFileName(txtFilePath.Text)
output = System.IO.File.Create(OutputFilePath)
bytesIn = 1
Do Until bytesIn < 1
bytesIn = stream.Read(buffer, 0, 1024)
If bytesIn > 0 Then
output.Write(buffer, 0, bytesIn)
totalBytesIn += bytesIn
lblDownloadedBytes.Text = totalBytesIn.ToString & " bytes"
If flLength > 0 Then
'=== Moved to bWorker_ProgressChanged.
'Dim perc As Integer = (totalBytesIn / flLength) * 100
'=== Now reports downloaded bytes in KB instead of percent.
bWorker.ReportProgress(CInt(totalBytesIn / 1024))
End If
End If
Loop
output.Close()
stream.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
'=== Completely reworked
Private Sub bWorker_ProgressChanged(ByVal sender As Object, _
ByVal e As System.ComponentModel.ProgressChangedEventArgs) _
Handles bWorker.ProgressChanged
Dim bytes As Long = 1024 * e.ProgressPercentage
'Can exceed 100% beacause of rounding effects
Dim percent As Integer = Math.Min(100, CInt(100 * bytes \ flLength))
pBar.Value = percent
lblPercent.Text = percent & "%"
lblDownloadedBytes.Text = FormatBytes(bytes)
Dim elapsedSeconds As Double = stopwatch.ElapsedMilliseconds / 1000
If elapsedSeconds > 0 Then
Dim speed As Double = bytes / elapsedSeconds
lblSpeed.Text = FormatBytes(CInt(speed)) & " / s"
End If
End Sub
Private Sub bWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bWorker.RunWorkerCompleted
MsgBox("Download Complete!")
End Sub
'=== New Function
Private Function FormatBytes(ByVal bytes As Long) As String
Dim sizes As String() = {"B", "KB", "MB", "GB", "TB", "PB", "EB"}
Dim order As Integer = 0
Dim len As Double = bytes
While len >= 1024 AndAlso order + 1 < sizes.Length
order += 1
len = len / 1024
End While
Return String.Format("{0:0.0} {1}", len, sizes(order))
End Function
End Class
See: How to: Use a Background Worker

Download File With Start / Pause / Stop

Is there any way i can pause a file download in my vb program?? I have tried both the http method and the my.computer.net method with no luck. I have also tried pausing the background worker by this method: [URL] But even if the bgworker is paused the download goes on.....
Dim locationfiledownload As String
Dim whereToSave As String 'Where the program save the file
Delegate Sub ChangeTextsSafe(ByVal length As Long, ByVal position As Integer, ByVal percent As Integer, ByVal speed As Double)
Delegate Sub DownloadCompleteSafe(ByVal cancelled As Boolean)
Public Sub DownloadComplete(ByVal cancelled As Boolean)
ToolStripButton2.Enabled = True
ToolStripButton3.Enabled = False
If cancelled Then
Me.Label4.Text = "Cancelled"
MessageBox.Show("Download aborted", "Aborted", MessageBoxButtons.OK, MessageBoxIcon.Information)
Else
Me.Label4.Text = "Successfully downloaded"
MessageBox.Show("Successfully downloaded!", "All OK", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
Me.RadProgressBar1.Value1 = 0
Me.Label4.Text = ""
End Sub
Public Sub ChangeTexts(ByVal length As Long, ByVal position As Integer, ByVal percent As Integer, ByVal speed As Double)
Me.Label4.Text = "Downloaded " & Math.Round((position / 1024), 2) & " KB of " & Math.Round((length / 1024), 2) & "KB"
Me.RadProgressBar1.Value1 = percent
End Sub
Public Sub btnDownload_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton2.Click
locationfiledownload = GetPage("http://asankonkur.ir/update/locationfiledownload.txt")
If locationfiledownload <> "" AndAlso locationfiledownload.StartsWith("http://") Then
Me.SaveFileDialog1.FileName = locationfiledownload.Split("/"c)(locationfiledownload.Split("/"c).Length - 1)
If Me.SaveFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
Me.whereToSave = Me.SaveFileDialog1.FileName
Me.SaveFileDialog1.FileName = ""
ToolStripButton2.Enabled = False
ToolStripButton3.Enabled = True
Me.BackgroundWorker2.RunWorkerAsync() 'Start download
End If
Else
MessageBox.Show("Please insert valid URL for download", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
End If
End Sub
Private Sub BackgroundWorker2_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker2.DoWork
'Creating the request and getting the response
Dim theResponse As HttpWebResponse
Dim theRequest As HttpWebRequest
Try 'Checks if the file exist
theRequest = WebRequest.Create(locationfiledownload)
theResponse = theRequest.GetResponse
Catch ex As Exception
MessageBox.Show("An error occurred while downloading file. Possibe causes:" & ControlChars.CrLf & _
"1) File doesn't exist" & ControlChars.CrLf & _
"2) Remote server error", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Dim cancelDelegate As New DownloadCompleteSafe(AddressOf DownloadComplete)
Me.Invoke(cancelDelegate, True)
Exit Sub
End Try
Dim length As Long = theResponse.ContentLength 'Size of the response (in bytes)
Dim safedelegate As New ChangeTextsSafe(AddressOf ChangeTexts)
Me.Invoke(safedelegate, length, 0, 0, 0) 'Invoke the TreadsafeDelegate
Dim writeStream As New IO.FileStream(Me.whereToSave, IO.FileMode.Create)
'Replacement for Stream.Position (webResponse stream doesn't support seek)
Dim nRead As Integer
'To calculate the download speed
Dim speedtimer As New Stopwatch
Dim currentspeed As Double = -1
Dim readings As Integer = 0
Do
If BackgroundWorker2.CancellationPending Then 'If user abort download
Exit Do
End If
speedtimer.Start()
Dim readBytes(4095) As Byte
Dim bytesread As Integer = theResponse.GetResponseStream.Read(readBytes, 0, 4096)
nRead += bytesread
Dim percent As Short = (nRead * 100) / length
Me.Invoke(safedelegate, length, nRead, percent, currentspeed)
If bytesread = 0 Then Exit Do
writeStream.Write(readBytes, 0, bytesread)
speedtimer.Stop()
readings += 1
If readings >= 5 Then 'For increase precision, the speed it's calculated only every five cicles
currentspeed = 20480 / (speedtimer.ElapsedMilliseconds / 1000)
speedtimer.Reset()
readings = 0
End If
Loop
'Close the streams
theResponse.GetResponseStream.Close()
writeStream.Close()
If Me.BackgroundWorker2.CancellationPending Then
IO.File.Delete(Me.whereToSave)
Dim cancelDelegate As New DownloadCompleteSafe(AddressOf DownloadComplete)
Me.Invoke(cancelDelegate, True)
Exit Sub
End If
Dim completeDelegate As New DownloadCompleteSafe(AddressOf DownloadComplete)
Me.Invoke(completeDelegate, False)
End Sub
Private Sub mainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Label4.Text = ""
End Sub
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton3.Click
Me.BackgroundWorker2.CancelAsync() 'Send cancel request
End Sub
In your code, you are using WebRequest.Create(locationfiledownload). By default, this creates a request header that asks for the entire file. You need to edit the request and add a Range header that asks for the specific byte range of the file you're looking for. E.g., adding to the WebRequest.Headers.Range.Ranges collection. Unfortunately, this is going to make your code quite a bit more complex as you will need to store details of what's already been download somewhere (assuming you want to resume after application close/restart). You'll need to know;
How much of the file (if any) is already downloaded
How much you intend downloading at any one time
Once you know this, you will have to form a request with a Range header for X bytes of the file. Once you receive it, you'll need to save it and ask for the next section. An example written in C# is available on The Code Project here: http://www.codeproject.com/Tips/307548/Resume-Suppoert-Downloading

Copy files with progress

I am wanting the most efficient way to copy a file with a progress bar updating the copy percentage.
This is the standard copy code I am using:
System.IO.File.Copy(source,target)
This is very fast and efficient. However, I cannot report the copy percentage.
I have tried many functions that read and save a file by opening up the filestream and then looping while reading/writing the data. This enables me to report the progress.
Here are the functions that I am using:
Public Sub SaveBinaryFile(strFilename As String, bytesToWrite() As Byte)
Dim position As Integer = 0
Dim BufferSize As Integer = 4096
'frmMain.tsProgressBar.Value = 0
Using fsNew As FileStream = New FileStream(strFilename, FileMode.Create, FileAccess.Write)
Do
Dim intToCopy As Integer = Math.Min(BufferSize, bytesToWrite.Length - position)
Dim buffer(intToCopy - 1) As Byte
Array.Copy(bytesToWrite, position, buffer, 0, intToCopy)
fsNew.Write(buffer, 0, buffer.Length)
'frmMain.tsProgressBar.Value = ((position / bytesToWrite.Length) * 100)
'frmMain.tsProgressBar.Refresh()
Application.DoEvents()
position += intToCopy
Loop While position < bytesToWrite.Length
End Using
End Sub
Public Function ReadBinaryFile(strFilename As String) As Byte()
Dim position As Integer = 0
Dim bufferSize As Integer = 4096
Dim bytes() As Byte
'frmMain.tsProgressBar.Value = 0
Using fsOpen As FileStream = New FileStream(strFilename, FileMode.Open)
ReDim bytes((fsOpen.Length) - 1)
Do
If (position + bufferSize) > fsOpen.Length Then
fsOpen.Read(bytes, position, fsOpen.Length - position)
Exit Do
Else
fsOpen.Read(bytes, position, bufferSize)
End If
'frmMain.tsProgressBar.Value = ((position / fsOpen.Length) * 100)
'frmMain.tsProgressBar.Refresh()
Application.DoEvents()
position += bufferSize
Loop
End Using
Return bytes
End Function
The problem is that is a lot slower than using the straight copy code.
What is the best/efficient way to copy a file showing the copy progress?
thanks
There is a variant of System.IO.File that provides user feedback; it's called Microsoft.VisualBasic.FileIO.FileSystem. See also http://msdn.microsoft.com/en-us/library/cc165446.aspx.
hmm Try this function
Dim D As Integer
Function CopyFileWithProgress(ByVal Source As String, ByVal Destination As String) As Integer
Try
Dim SourceF As New IO.FileStream(TextBox1.Text, IO.FileMode.Open)
Dim DestinationF As New IO.FileStream(TextBox2.Text & "\" & TextBox3.Text & ".ps4game", IO.FileMode.Create)
Dim len As Long = SourceF.Length - 1
Dim buffer(1024) As Byte
Dim byteCFead As Integer
While SourceF.Position < len
byteCFead = (SourceF.Read(buffer, 0, 1024))
DestinationF.Write(buffer, 0, byteCFead)
D = CInt(SourceF.Position / len * 100)
Application.DoEvents()
End While
DestinationF.Flush()
DestinationF.Close()
SourceF.Close()
Return D
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Function
it will work
you can use:
Microsoft.VisualBasic.FileIO.FileSystem.CopyFile("C:\[Copy From]", "C:\[Copy To]", _
FileIO.UIOption.AllDialogs)
' this requires the Microsoft.VisualBasic.dll, which is referenced from Visual Basic .NET
' projects by default, but needs to be added to C# projects manually
OR :
Dim CF As New IO.FileStream("C:\[Copy From]", IO.FileMode.Open)
Dim CT As New IO.FileStream("C:\[Copy To]", IO.FileMode.Create)
Dim len As Long = CF.Length - 1
Dim buffer(1024) As Byte
Dim byteCFead As Integer
While CF.Position < len
byteCFead = (CF.Read(buffer, 0, 1024))
CT.Write(buffer, 0, byteCFead)
ProgressBar1.Value = CInt(CF.Position / len * 100)
Application.DoEvents()
End While
CT.Flush()
CT.Close()
CF.Close()
OR : Using WebClient
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Not OpenFileDialog1.ShowDialog() = DialogResult.OK Then Return
If Not FolderBrowserDialog1.ShowDialog = DialogResult.OK Then Return
Button1.Enabled = False
WebClient1.DownloadFileAsync(New Uri(OpenFileDialog1.FileName), Path.Combine(FolderBrowserDialog1.SelectedPath, OpenFileDialog1.SafeFileName))
End Sub
Private Sub WebClient1_DownloadProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs) Handles WebClient1.DownloadProgressChanged
ProgressBar1.Value = e.ProgressPercentage
End Sub
Private Sub WebClient1_DownloadFileCompleted(sender As Object, e As System.ComponentModel.AsyncCompletedEventArgs) Handles WebClient1.DownloadFileCompleted
Button1.Enabled = True
End Sub