实现具有进度反馈和断点续传功能的文件下载器

在工作项目中,需要从给定的URL下载文件。遗憾的是,WebClient类提供的方法除了下载数据外,没有提供任何额外的功能。需要的不仅仅是下载,还需要能够提供进度反馈,并且支持断点续传。

在Web上搜索现有代码时,找到了CodeProject上的两篇文章,它们帮助接近所需要的功能。第一篇文章是John Batte写的,第二篇是Phil Crosby基于John Batte的工作衍生出来的。利用这两篇文章作为起点,进行了进一步的衍生,实现了目标。

本文的代码示例和内容专注于.NET 2.0实现,任何代码更新都只针对该版本。.NET 1.1实现仅用于向后兼容,没有计划继续对其进行更改。

使用代码

FileDownloader类是主要的类,使用起来非常简单。最小实现如下:

private void DoDownload() { FileDownloader downloader = new FileDownloader(); downloader.Download(new Uri("http://www.codeproject.com/info/stuff/cp_bg_black1024.gif"), @"C:\Temp"); }

这将创建FileDownloader类的一个新实例,并下载位于"http://www.codeproject.com/info/stuff/cp_bg_black1024.gif"的文件到"C:\Temp"文件夹。

FileDownloader实际上执行所有下载操作都是异步的。当调用FileDownloader.Download(Uri url, string destinationFolder)方法时,它通过等待一个信号来完成同步下载,该信号指示下载已完成。这允许通过使用Download方法进行同步下载,或者通过使用DownloadAsync方法进行异步下载。同步和异步方法最终都调用同一个内部方法来执行实际的下载。

这个内部方法叫做DownloadAsyncCore,它实例化了一个DownloadInfo内部类。这个类与.NETCLR提供的FileInfo类性质相似,为FileDownloader提供了实际下载文件所需的所有信息。包括:

  • 如果已知,正在下载的文件的长度
  • 用于实际下载文件的Stream
  • 服务请求的WebResponse

一旦DownloadInfo类被实例化,数据就会以1KB的块大小下载并写入磁盘。这是默认的块大小,可以通过BlockSize属性进行更改。正是这种实现方式允许下载在被取消或中断时可以恢复。

虽然这种实现是功能性的,但它确实阻止了任何在代理后面或需要身份验证才能访问请求的URL的人使用该类。为了支持这些场景,FileDownloader类提供了一个Proxy属性,该属性接受一个派生自IWebProxy的对象,以及一个Credentials属性,该属性接受一个派生自ICredentials的对象。这些属性也被传递给底层的DownloadInfo对象。

最后,事件提供了进度反馈。.NET2.0中的WebClient类具有异步下载方法,提供了这样的事件。这些方法由DownloadCompletedEventArgs和DownloadProgressChangedEventArgs EventArgs派生类服务。不幸的是,这两个类都有内部构造函数,并且是.NET 2.0中的新内容,所以无法使用它们。相反,创建了一个新的EventArgs派生类三元组来处理FileDownloader类公开的三个事件。这些事件是:

public event EventHandler DownloadCompleted; public event EventHandler DownloadProgressChanged; public event EventHandler DownloadStatusChanged;

这些事件在实际文件下载过程中被引发,以便为调用者提供状态信息(DownloadStatusChanged)、进度信息(DownloadProgressChanged)和完成信息(DownloadCompleted)。

以下是一个完整的示例:

private void DoDownload() { Uri fileUrl = new Uri("http://www.codeproject.com/info/stuff/cp_bg_black1024.gif"); string tempPath = Path.GetTempPath(); string fileName = Path.GetFileName(fileUrl.AbsoluteUri); string downloadPath = Path.Combine(tempPath, fileName); FileDownloader downloader = new FileDownloader(); downloader.Proxy = WebRequest.DefaultWebProxy; downloader.Credentials = CredentialCache.DefaultCredentials; downloader.DownloadCompleted += new EventHandler(OnDownloadCompleted); downloader.DownloadProgressChanged += new EventHandler(OnDownloadProgressChanged); downloader.DownloadStatusChanged += new EventHandler(OnDownloadStatusChanged); downloader.Download(fileUrl, tempPath); }

以下是使用VB.NET的相同示例。这个示例基于CBlackburn的注释。

Private Sub DoDownload() Dim fileUrl As Uri = New Uri("http://www.codeproject.com/info/stuff/cp_bg_black1024.gif") Dim tempPath As String = Path.GetTempPath() Dim fileName As String = Path.GetFileName(fileUrl.AbsoluteUri) Dim downloadPath As String = Path.Combine(tempPath, fileName) Dim downloader As FileDownloader = New FileDownloader() downloader.Proxy = WebRequest.DefaultWebProxy downloader.Credentials = CredentialCache.DefaultCredentials AddHandler downloader.DownloadCompleted, AddressOf OnDownloadCompleted AddHandler downloader.DownloadProgressChanged, AddressOf OnDownloadProgressChanged AddHandler downloader.DownloadStatusChanged, AddressOf OnDownloadStatusChanged downloader.Download(fileUrl, tempPath) End Sub
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485