65.9K
CodeProject 正在变化。 阅读更多。
Home

VB.NET 后台文件下载器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (36投票s)

2009年4月22日

GPL3

3分钟阅读

viewsIcon

220074

downloadIcon

21914

一个多线程文件下载器,包含进度详情、速度信息等

fileDownloader-downloading.gif

引言

这个类使您可以轻松地在后台(通过单独的线程)下载多个文件,并将提供有关已下载数据量、完成百分比和下载速度的信息。最重要的是,您可以取消下载、暂停下载,当然也可以恢复下载。请注意,还有一个 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 

下载器还提供了一些属性来指示其当前状态:IsBusyIsPausedCanStartCanStopCanPauseCanResume(都是布尔值)。 这里有一个如何使用它们来设置界面的例子

' 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。 在创建此类之前,我没有意识到对象会被锁定并且并非总是可以通过所有线程设置而无需适当的额外代码。 我也从未使用过 BackGroundWorkerReportProgress 事件。 在创建此类之后,我阅读了更多关于多线程的文章,以更好地掌握它,我可以推荐以下系列文章: .NET 线程新手指南第 1 部分(共 n 部分)。 我希望这篇文章能够帮助其他人,并获得一些关于如何改进类本身的批评性反馈。

我希望尽快实现更多功能,包括取消下载而不删除文件以及之后恢复下载的选项,以及同时在单独的线程上下载多个文件的能力。

历史

  • 2009 年 5 月 20 日:发布了 1.0.3 版本并更新了本文
  • 2009 年 4 月 30 日:在我的论坛上发布了 1.0.2 版本(添加了 PackageSizeStopWatchCyclesAmount 属性)
  • 2009 年 4 月 22 日:发布了本文的第一个版本
  • 2009 年 4 月 21 日:发布了该类
    • 对于此代码所基于的内容(可以看作是较旧版本),请参阅 这篇文章

参考文献

  • 可以在 这里 找到对此类的荷兰语支持。
  • 如果我只是稍微更新了代码,我不会更新这篇文章,只会 在这里 发布它。
© . All rights reserved.