VB.NET 后台文件下载器






4.80/5 (36投票s)
一个多线程文件下载器,包含进度详情、速度信息等

引言
这个类使您可以轻松地在后台(通过单独的线程)下载多个文件,并将提供有关已下载数据量、完成百分比和下载速度的信息。最重要的是,您可以取消下载、暂停下载,当然也可以恢复下载。请注意,还有一个 C# 版本的此类 可用。
背景
我开始开发这个类,是因为编程帮助论坛上有人问如何最好地在后台下载文件。我获得了很多想法,并且部分代码基于 在 .NET 中下载文件并包含所有信息 这篇文章,作者是 Carmine_XX。这个类增加了对多个文件的支持、逻辑/布局抽象,并且设计成易于使用。
使用代码
一旦您将此类添加到您的项目中,您应该能够通过命名空间 Bn.Classes
访问它。 您当然可以根据自己的喜好调整命名空间或完全删除它。
使用此类时,您需要做的第一件事是(从逻辑上讲)创建一个新实例,然后添加您想要下载的文件。您还需要设置要下载到的本地目录。 这很简单。
' Creating a new instance of a FileDownloader
Private WithEvents downloader As New FileDownloader
' A simple implementation of setting the directory path,
' adding files from a textbox and starting the download
Private Sub btnStart_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnStart.Click
Dim openFolderDialog As New FolderBrowserDialog
With downloader
If openFolderDialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
.Files.Clear()
.LocalDirectory = openFolderDialog.SelectedPath
For Each path As String In txtFilesToDownload.Lines
' The FileInfo structure will parse your path,
' and split it to the path itself and the file name,
' which will both be available for you
.Files.Add(New FileDownloader.FileInfo(path))
Next
.Start()
End If
End With
End Sub
暂停、恢复或取消下载所需的代码再简单不过了
Private Sub btnPauze_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnPauze.Click
' Pause the downloader
downloader.Pause()
End Sub
Private Sub btnResume_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnResume.Click
' Resume the downloader
downloader.Resume()
End Sub
Private Sub btnStop_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnStop.Click
' Stop the downloader
' Note: This will not be instantaneous - the current requests need to
' be closed down, and the downloaded files need to be deleted
downloader.Stop()
End Sub
下载器还提供了一些属性来指示其当前状态:IsBusy
、IsPaused
、CanStart
、CanStop
、CanPause
和 CanResume
(都是布尔值)。 这里有一个如何使用它们来设置界面的例子
' This event is fired every time the paused or busy state is changed,
' and used here to set the controls of the interface
Private Sub downloader_StateChanged() _
Handles downloader.StateChanged 'This is equal to: Handles
'downloader.IsBusyChanged, downloader.IsPausedChanged
' Setting the buttons
btnStart.Enabled = downloader.CanStart
btnStop.Enabled = downloader.CanStop
btnPauze.Enabled = downloader.CanPause
btnResume.Enabled = downloader.CanResume
' Enabling or disabling the setting controls
txtFilesToDownload.ReadOnly = downloader.IsBusy
cbUseProgress.Enabled = Not downloader.IsBusy
End Sub
这是显示进度信息的演示代码
' Occurs every time a block of data has been downloaded,
' and can be used to display the progress with
' Note that you can also create a timer, and display the progress
' every certain interval
' Also note that the progress properties return a size in bytes,
' which is not really user friendly to display
' The FileDownloader class provides shared functions to format these
' byte amounts to a more readable format, either in binary or decimal notation
Private Sub downloader_ProgressChanged() Handles downloader.ProgressChanged
pBarFileProgress.Value = CInt(downloader.CurrentFilePercentage)
lblFileProgressDetails.Text = String.Format("Downloaded {0} of {1} ({2}%)", _
FileDownloader.FormatSizeBinary(downloader.CurrentFileProgress), _
FileDownloader.FormatSizeBinary(downloader.CurrentFileSize), _
downloader.CurrentFilePercentage) & String.Format(" - {0}/s", _
FileDownloader.FormatSizeBinary(downloader.DownloadSpeed))
If downloader.SupportsProgress Then
pBarTotalProgress.Value = CInt(downloader.TotalPercentage)
lblTotalProgressDetails.Text = _
String.Format("Downloaded {0} of {1} ({2}%)", _
FileDownloader.FormatSizeBinary(downloader.TotalProgress), _
FileDownloader.FormatSizeBinary(downloader.TotalSize), _
downloader.TotalPercentage)
End If
End Sub
另一个值得注意的代码片段是如何设置 SupportsProgress
属性。
' Setting the SupportsProgress property -
' if set to false, no total progress data will be available!
Private Sub cbUseProgress_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cbUseProgress.CheckedChanged
downloader.SupportsProgress = cbUseProgress.Checked
End Sub
当 SupportProgress
属性设置为 true
时,文件大小将在任何下载开始之前计算。 这可能需要一段时间,尤其是当您有大量文件时。 FileDownloader
类会在每次开始检查文件大小时触发一个事件,该事件可用于显示进度。
' Show the progress of file size calculation
Private Sub downloader_CalculationFileSize(ByVal sender As Object, _
ByVal fileNumber As Int32) Handles downloader.CalculatingFileSize
lblStatus.Text = String.Format("Calculating file sizes - _
file {0} of {1}", fileNumber, downloader.Files.Count)
End Sub

值得关注的点
当我开始开发这个类时,我以为经过一天的开发就可以完成了。 但是我遇到了一些问题,包括我对多线程的一个错误假设,以及您一次只能有两个打开的 HttpWebResponse
。 在创建此类之前,我没有意识到对象会被锁定并且并非总是可以通过所有线程设置而无需适当的额外代码。 我也从未使用过 BackGroundWorker
的 ReportProgress
事件。 在创建此类之后,我阅读了更多关于多线程的文章,以更好地掌握它,我可以推荐以下系列文章: .NET 线程新手指南第 1 部分(共 n 部分)。 我希望这篇文章能够帮助其他人,并获得一些关于如何改进类本身的批评性反馈。
我希望尽快实现更多功能,包括取消下载而不删除文件以及之后恢复下载的选项,以及同时在单独的线程上下载多个文件的能力。
历史
- 2009 年 5 月 20 日:发布了 1.0.3 版本并更新了本文
- 2009 年 4 月 30 日:在我的论坛上发布了 1.0.2 版本(添加了
PackageSize
和StopWatchCyclesAmount
属性) - 2009 年 4 月 22 日:发布了本文的第一个版本
- 2009 年 4 月 21 日:发布了该类
- 对于此代码所基于的内容(可以看作是较旧版本),请参阅 这篇文章。