我正在尝试创建一个支持暂停和恢复功能的winform vb.net下载程序,如果在下载操作期间未单击“暂停”和“恢复”按钮,程序可以正常工作并下载文件而不会出错。但如果在下载操作期间单击暂停和继续按钮,则下载的文件将出错。如果它是一个mp3文件,它会在下载操作暂停的确切位置进行加扰(尽管它会在该点之后继续播放)。对于.zip / .rar文件,解压缩时会出现i校验和错误。我的代码:
Imports System.ComponentModel
Imports System.Net
Imports System.IO
Public Class downloadformclass
#Region "Declarations"
Dim whereToSave As String
Private _filename As String
Private _address As String
Public savedialogresponse As Boolean
Delegate Sub updatesafe(size As Double, downloadposition As Integer, speed As Double, percent As Integer)
Delegate Sub downloadstatusdelegate(value As Boolean)
Public WithEvents BackgroundWorkers As BackgroundWorker
Private downloadposition As Integer = 0
Private filesize As Long = 0
Dim j As Integer = 0
Private totalnumberofbytesread As Integer = 0
Private previouspositon As Long = 0
Private previouspercent As Integer = 0
Private previousspeed As Double = 0
Dim canceldelegate As New downloadstatusdelegate(AddressOf downloadstatus)
Private path As String
Dim WithEvents k As New Dictionary(Of String, Object)
Dim request As HttpWebRequest
Dim response As HttpWebResponse
Dim bannersarray As ArrayList
Dim objMySQLConnect As New MySQLConnect
Dim rand As New Random
Delegate Sub safeadvertshow(objadvertbanner As Object)
#End Region
#Region "Overides"
Public Overrides Function ToString() As String
Return MyBase.Tag
End Function
#End Region
#Region "Property"
Public Property filename As String
Get
Return _filename
End Get
Set(value As String)
_filename = value
End Set
End Property
Public Property address As String
Get
Return _address
End Get
Set(value As String)
_address = value
End Set
End Property
#End Region
#Region "Form events"
Private Sub downloadformclass_Load(sender As Object, e As EventArgs) Handles Me.Load
BackgroundWorker1.RunWorkerAsync()
' Timer1.Interval = 30000
'Timer1.Start()
End Sub
#End Region
' starts the background thread
#Region "Functions"
Public Function savedialog()
SaveFileDialog1.FileName = filename
SaveFileDialog1.Filter = "All files (*.*)|*.*"
SaveFileDialog1.DefaultExt = "rar"
SaveFileDialog1.AddExtension = True
If SaveFileDialog1.ShowDialog() = DialogResult.OK Then
path = SaveFileDialog1.FileName
savedialogresponse = True
BackgroundWorkers = New BackgroundWorker
BackgroundWorkers.WorkerSupportsCancellation = True
AddHandler BackgroundWorkers.DoWork, AddressOf BackgroundWorker1_DoWork
k(Tag) = BackgroundWorkers
k(Tag).RunWorkerAsync()
Button3.Enabled = False
Else
savedialogresponse = False
End If
Return savedialogresponse
End Function
#End Region
#Region "Background Thread and Methods for file streaming"
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs)
Dim bytesreadbuffer(4095) As Byte
Dim numberofbytesread As Integer
Dim percent As Integer = 0
Dim clock As New Stopwatch
Dim speed As Double = 0
Dim readings As Integer = 0
Dim downloadfile As FileStream
bytesreadbuffer(4095) = Nothing
j = j + 1
If downloadposition <> 0 Then
downloadfile = New FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)
Else
downloadfile = New FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)
End If
Try
request = WebRequest.Create(address)
If downloadposition > 0 Then
request.AddRange(downloadposition, filesize)
Else
request.AddRange(downloadposition)
End If
request.Proxy = Nothing
request.ReadWriteTimeout = 60000
response = request.GetResponse
Catch ex As WebException
MessageBox.Show("Error !!No network connection" & ex.Message)
Me.Invoke(canceldelegate, True)
j = 0
Exit Sub
End Try
Dim safeupdate As New updatesafe(AddressOf updatelabelsandprogressbar)
If j = 1 And downloadposition = 0 Then
filesize = response.ContentLength
End If
Me.Invoke(safeupdate, filesize, downloadposition, 0, 0)
Do
If totalnumberofbytesread = filesize Then
Exit Do
End If
If k(Tag).CancellationPending = True Then
Exit Do
End If
clock.Start()
Try
numberofbytesread = response.GetResponseStream.Read(bytesreadbuffer, 0, 4096)
Catch ex As Exception
MessageBox.Show(ex.Message)
k(Tag).CancelAsync()
End Try
downloadfile.Write(bytesreadbuffer, 0, numberofbytesread)
totalnumberofbytesread = totalnumberofbytesread + numberofbytesread
percent = (totalnumberofbytesread / filesize) * 100
Try
Me.Invoke(safeupdate, filesize, totalnumberofbytesread, speed, percent)
Catch ex As Exception
k(Tag).CancelAsync()
End Try
clock.Stop()
readings = readings + 1
If readings >= 5 Then
speed = 20480 / (clock.ElapsedMilliseconds / 1000)
clock.Reset()
readings = 0
End If
Loop
response.GetResponseStream.Close()
downloadfile.Dispose()
If k(Tag).CancellationPending = True Then
Try
downloadposition = totalnumberofbytesread
Me.Invoke(canceldelegate, True)
Catch ex As Exception
File.Delete(path)
Exit Sub
End Try
Exit Sub
End If
Me.Invoke(canceldelegate, False)
End Sub
Public Sub downloadstatus(d As Boolean)
If d = True Then
Button3.Enabled = True
Button2.Enabled = False
MessageBox.Show("download paused")
Else
Button3.Enabled = False
Button2.Enabled = False
MessageBox.Show("download complete")
End If
End Sub
Private Sub updatelabelsandprogressbar(size As Long, downloadposition As Long, speed As Double, percent As Integer)
Try
Me.Refresh()
Label1.Text = "Progress : " & percent & "%"
Label2.Text = "Downloaded:" & downloadposition & " KB of " & size & "KB"
Label3.Text = "Speed: " & Math.Round((speed / 1024), 2) & " KB/s"
ProgressBar1.Value = percent
Catch ex As Exception
MessageBox.Show("An Error occured: " & ex.Message)
End Try
End Sub
#End Region
#Region "Button Clicks event"
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
request.Abort()
End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
k(Tag).RunWorkerAsync()
Button3.Enabled = False
Button2.Enabled = True
End Sub
#End Region
#Region "Timer events/advert"
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Try
' BackgroundWorker1.RunWorkerAsync()
Catch ex As Exception
'' MessageBox.Show("hanging because we r busy")
End Try
End Sub
Private Sub BackgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim objadvertbanner As New advertbannerclass
bannersarray = New ArrayList
' bannersarray = MySQLConnect.getadvertbanners
' objadvertbanner = bannersarray(rand.Next(0, 1)) 'bannersarray.Count
Dim objsafeadvertshow As New safeadvertshow(AddressOf advertshow)
Me.Invoke(objsafeadvertshow, objadvertbanner)
End Sub
Public Sub advertshow(objadvertbanner As Object)
If objadvertbanner.bannerpath = "waitingforaddress" Then
PictureBox1.Image = My.Resources.loading
PictureBox1.Tag = Nothing
PictureBox1.Cursor = Cursors.Default
Else
Try
PictureBox1.Load(objadvertbanner.bannerpath)
PictureBox1.Tag = objadvertbanner.bannerurllink
If PictureBox1.Tag = Nothing Then
PictureBox1.Cursor = Cursors.Default
Else
PictureBox1.Cursor = Cursors.Hand
End If
Catch ex As Exception
PictureBox1.Image = Nothing
PictureBox1.Tag = Nothing
End Try
End If
End Sub
Private Sub PictureBox1_Click(sender As Object, e As EventArgs) Handles PictureBox1.Click
Try
Process.Start(sender.Tag.ToString)
Catch ex As Exception
End Try
End Sub
#End Region
End Class
答案 0 :(得分:0)
终于找到了解决方案,它现在按预期工作,我添加了代码:
numberofbytesread = numberofbytesread - numberofbytesread
到catch块内的do循环。单击暂停按钮时,&#34;请求&#34;如button2.click事件中所示中止。但是当发生这种情况时,它很可能会尝试将数据读入缓冲区,所以我发现这个缓冲区中包含的数据会因点击暂停按钮而被破坏。因此代码&#34; numberofbytesread = numberofbytesread - numberofbytesread&#34;确保在请求终止时不会将任何内容写入文件流。完整的do循环代码是:
Do
If totalnumberofbytesread = filesize Then
Exit Do
End If
If k(Tag).CancellationPending = True Then
Exit Do
End If
clock.Start()
Try
numberofbytesread = response.GetResponseStream.Read(bytesreadbuffer, 0, 4096)
Catch ex As Exception
MessageBox.Show(ex.Message)
k(Tag).CancelAsync()
numberofbytesread = numberofbytesread - numberofbytesread
End Try
downloadfile.Write(bytesreadbuffer, 0, numberofbytesread)
totalnumberofbytesread = totalnumberofbytesread + numberofbytesread
percent = (totalnumberofbytesread / filesize) * 100
Try
Me.Invoke(safeupdate, filesize, totalnumberofbytesread, speed, percent)
Catch ex As Exception
k(Tag).CancelAsync()
End Try
clock.Stop()
readings = readings + 1
If readings >= 5 Then
speed = 20480 / (clock.ElapsedMilliseconds / 1000)
clock.Reset()
readings = 0
End If
Loop