在 .NET 中下载文件,包含所有信息:进度条、下载速度、支持取消和恢复






4.56/5 (39投票s)
如何在 .NET 中下载文件,并显示所有进度信息(进度条、下载速度),支持取消和恢复

介绍
我将解释如何使用 .NET Framework 构建一个完整、可靠和强大的下载管理器。
它能够显示下载过程中的各种数据,包括下载速度、文件大小、已下载大小和完成百分比。
已经基于此代码编写了一个全新的类,它具有逻辑/布局抽象、多文件下载支持,并且通过提供各种属性和事件而更易于使用。查看FileDownloader 文章。
文件通过 HttpWebRequest
和 HttpWebResponse
下载,并使用 StreamWriter
写入文件。所有这些都在单独的线程(使用 BackgroundWorker
)中完成,因此使用此下载器的应用程序不会冻结。
使用代码
演示应用程序非常简单,仅包含下载文件所需的 UI 组件。您当然可以在自己的应用程序中实现此下载器,或者只是使用它在后台下载,而无需任何用户交互。
最重要的代码可以在 BackgroundWorker
的 DoWork
方法中找到。首先,会尝试建立与文件的连接。如果成功,Do
循环中的脚本将开始逐块下载文件,直到没有剩余字节要下载。请注意,一旦收到一个数据块,它就会被写入本地目标文件。
Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, _
ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.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(Me.txtFileName.Text)
theResponse = theRequest.GetResponse
Catch ex As Exception
MessageBox.Show("An error occurred while downloading file. _
Possible 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 BackgroundWorker1.CancellationPending Then 'If user aborts 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 is calculated only every five cycles
currentspeed = 20480 / (speedtimer.ElapsedMilliseconds / 1000)
speedtimer.Reset()
readings = 0
End If
Loop
'Close the streams
theResponse.GetResponseStream.Close()
writeStream.Close()
If Me.BackgroundWorker1.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
此代码使用委托来调用主线程上的方法,并将有关下载进度的数据传递给它们。
此代码不支持 FTP 下载,但可以轻松修改以支持此功能。
恢复下载
可以修改代码以允许恢复下载。在第一次使用 HttpWebRequest
对象之前添加此代码。
theRequest.AddRange(whereYouWantToStart) '<- add this
您还需要将 FileStream
实例的 Position
属性设置为要恢复下载的位置。因此,请确保在取消下载之前也保存此位置。
Dim writeStream As New IO.FileStream(Me.whereToSave, IO.FileMode.Open)
writeStream.Position = whereYouWantToStart
计算速度
该代码包含内置的下载速度计算,使用 StopWatch
类。这将每下载 5 个数据包返回另一个结果。请注意,您也可以手动计算速度,并使用计时器以更规则的间隔获取数据。