C# .NET 后台文件下载器






4.91/5 (21投票s)
一个具有进度详情、速度信息等的多线程文件下载器

引言
这个类允许您轻松地在后台(通过单独的线程)下载多个文件,并提供关于下载数据量、完成百分比和下载速度的信息。最重要的是,您可以取消下载、暂停下载,当然还可以恢复下载。
背景
在编程帮助论坛上有人询问如何最好地在后台下载文件后,我开始编写这个类。我最初是用 VB.NET 编写的,但现在创建了一个 C# 实现。查看VB.NET 后台文件下载器文章获取原始代码。与原始 VB.NET 实现的另一个不同之处是,此代码使用 WPF 演示应用程序,而不是基于 Windows Forms 的应用程序。
Using the Code
一旦你将该类添加到你的项目,你应该能够通过该项目的命名空间访问它。
使用这个类时,你需要做的第一件事是(逻辑上)创建一个新的实例,然后添加你要下载的文件。你还需要设置你想要下载到的本地目录。这非常简单直接。
// Creating a new instance of a FileDownloader
private FileDownloader downloader = new FileDownloader();
你还需要向需要下载的列表中添加一些文件。这个例子演示了如何读取 WPF RichTextBox
的每一行并将其添加到列表中。
// A simple implementation of setting the directory path,
// adding files from a textbox and starting the download
private void btnStart_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.FolderBrowserDialog openFolderDialog =
new System.Windows.Forms.FolderBrowserDialog();
if (openFolderDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
// Set the path to the local directory where the files will be downloaded to
downloader.LocalDirectory = openFolderDialog.SelectedPath;
// Clear the current list of files (in case it's not the first download)
downloader.Files.Clear();
// Get the contents of the rich text box
string rtbContents = new TextRange(rtbPaths.Document.ContentStart,
rtbPaths.Document.ContentEnd).Text;
foreach (string line in rtbContents.Split('\n'))
{
String trimmedLine = line.Trim(' ', '\r');
if (trimmedLine.Length > 0)
{
// If the line is not empty, assume it's a valid URL
// and add it to the files list
// Note: You could check if the URL is valid before adding it,
// and probably should do this is a real application
downloader.Files.Add(new FileDownloader.FileInfo(trimmedLine));
}
}
// Start the downloader
downloader.Start();
}
}
注意:本文中的示例代码适用于 C# WPF 应用程序,对于 C# Forms 应用程序来说会略有不同。
然后暂停、恢复或取消下载所需的代码再简单不过了
private void btnPause_Click(object sender, RoutedEventArgs e)
{
// Pause the downloader
downloader.Pause();
}
private void btnResume_Click(object sender, RoutedEventArgs e)
{
// Resume the downloader
downloader.Resume();
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
// 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();
}
下载器还提供了一些属性来指示其当前状态: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
// This makes it equivalent to a void handling both
// downloader.IsBusyChanged and downloader.IsPausedChanged
private void downloader_StateChanged(object sender, EventArgs e)
{
// Setting the buttons
btnStart.IsEnabled = downloader.CanStart;
btnStop.IsEnabled = downloader.CanStop;
btnPause.IsEnabled = downloader.CanPause;
btnResume.IsEnabled = downloader.CanResume;
// Enabling or disabling the setting controls
rtbPaths.IsReadOnly = downloader.IsBusy;
cbUseProgress.IsEnabled = !downloader.IsBusy;
}
这是显示进度信息的演示代码
// Occurs every time of 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 static functions to format
// these byte amounts to a more readable format, either in binary or decimal notation
private void downloader_ProgressChanged(object sender, EventArgs e)
{
pBarFileProgress.Value = downloader.CurrentFilePercentage();
lblFileProgress.Content = 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)
{
pBarTotalProgress.Value = downloader.TotalPercentage();
lblTotalProgress.Content = String.Format("Downloaded {0} of {1} ({2}%)",
FileDownloader.FormatSizeBinary(downloader.TotalProgress),
FileDownloader.FormatSizeBinary(downloader.TotalSize),
downloader.TotalPercentage());
}
}
另一个值得注意的代码片段是如何设置 SupportsProgress
属性。
// Setting the SupportsProgress property - if set to false,
// no total progress data will be available!
private void cbUseProgress_Checked(object sender, RoutedEventArgs e)
{
downloader.SupportsProgress = (Boolean)cbUseProgress.IsChecked;
}
当 SupportProgress
属性设置为 true
时,文件大小将在任何下载开始之前计算。这可能需要一段时间,特别是当您有大量文件时。FileDownloader
类会在每次开始检查文件大小时触发一个事件,该事件可用于显示进度。
// Show the progress of file size calculation
// Note that these events will only occur when the total file size is
// calculated in advance, in other words when the SupportsProgress is set to true
private void downloader_CalculationFileSize(object sender, Int32 fileNr)
{
lblStatus.Content = String.Format("Calculating file sizes -
file {0} of {1}", fileNr, downloader.Files.Count);
}
关注点
将我的 VB.NET 类翻译成 C# 的主要原因是为了完全熟悉 C# 及其与 VB.NET 的区别,并练习一些 WPF 基础知识。
我希望尽快实现更多的功能,包括在不删除文件的情况下取消下载,以及之后恢复下载的选项,以及在单独的线程上同时下载多个文件的能力。
历史
- 2009 年 5 月 2 日:发布了 C# 类和这篇文章
- 2009 年 4 月 22 日:发表了一篇关于 VB.NET 类的文章
- 2009 年 4 月 21 日:发布了 VB.NET 类
- 对于原始 VB.NET 类所基于的代码(可以看作是旧版本),请参阅这篇文章。
参考文献
- 可以在这里找到对该类的荷兰语支持。