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

C# .NET 后台文件下载器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (21投票s)

2009年4月27日

GPL3

3分钟阅读

viewsIcon

140330

downloadIcon

13600

一个具有进度详情、速度信息等的多线程文件下载器

FileDownloaderDemo-downloading.gif

引言

这个类允许您轻松地在后台(通过单独的线程)下载多个文件,并提供关于下载数据量、完成百分比和下载速度的信息。最重要的是,您可以取消下载、暂停下载,当然还可以恢复下载。

背景

在编程帮助论坛上有人询问如何最好地在后台下载文件后,我开始编写这个类。我最初是用 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();
} 

下载器还提供了一些属性来指示其当前状态:IsBusyIsPausedCanStartCanStopCanPause 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);
}

FileDownloaderDemo-calculating.gif

关注点

将我的 VB.NET 类翻译成 C# 的主要原因是为了完全熟悉 C# 及其与 VB.NET 的区别,并练习一些 WPF 基础知识。

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

历史

  • 2009 年 5 月 2 日:发布了 C# 类和这篇文章
  • 2009 年 4 月 22 日:发表了一篇关于 VB.NET 类的文章
  • 2009 年 4 月 21 日:发布了 VB.NET 类
    • 对于原始 VB.NET 类所基于的代码(可以看作是旧版本),请参阅这篇文章

参考文献

  • 可以在这里找到对该类的荷兰语支持。
© . All rights reserved.