zoukankan      html  css  js  c++  java
  • 一个简单的利用 WebClient 异步下载的示例(二)

    继上一篇 一个简单的利用 WebClient 异步下载的示例(一) 后,我想把核心的处理提取出来,成 SkyWebClient,如下:

    1. SkyWebClient

    该构造函数中 downloadConfigs 参数是必须的,不能为 NULL,而 ProgressBar progressBar 可为空,只不过不能显示进度条而已。

        public class DownloadEntry
        {
            public string Url { get; set; }
    
            public string Path { get; set; }
    
            /// <summary>
            /// 当前处理的数据
            /// </summary>
            public object Data { get; set; }
    
            public DownloadEntry(string url, string savedPath)
                :this(url,savedPath, null)
            {
    
            }
    
            public DownloadEntry(string url, string savedPath, object data)
            {
                Url = url;
                Path = savedPath;
                Data = data;
            }
        }
    
        /// <summary>
        /// 当单个下载前的事件处理
        /// </summary>
        /// <param name="current">当前处理的数据,有可能为 NULL,请注意判断</param>
        public delegate void WhenSingleDownloadingEventHandler(DownloadEntry current);
    
        /// <summary>
        /// 当全部下载完毕后的事件处理
        /// </summary>
        public delegate void WhenAllDownloadedEventHandler();
    
        /// <summary>
        /// 当下载错误时
        /// </summary>
        /// <param name="ex"></param>
        public delegate void WhenDownloadingErrorEventHandler(Exception ex);
    
        public class SkyWebClient : INotifyPropertyChanged
        {
            #region 字段、属性
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string prop)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(prop));
                }
            }
    
            /// <summary>
            /// 当单个下载前的事件处理
            /// </summary>
            public event WhenSingleDownloadingEventHandler WhenSingleDownloading;
            private void OnWhenSingleDownloading(DownloadEntry next)
            {
                if (WhenSingleDownloading != null)
                {
                    WhenSingleDownloading(next);
                }
            }
    
            /// <summary>
            /// 当全部下载完毕后的事件处理
            /// </summary>
            public event WhenAllDownloadedEventHandler WhenAllDownloaded;
            private void OnWhenAllDownloaded()
            {
                if (WhenAllDownloaded != null)
                {
                    WhenAllDownloaded();
                }
            }
    
            /// <summary>
            /// 当全部下载完毕后的事件处理
            /// </summary>
            public event WhenDownloadingErrorEventHandler WhenDownloadingError;
            private void OnWhenDownloadingError(Exception ex)
            {
                if (WhenDownloadingError != null)
                {
                    WhenDownloadingError(ex);
                }
            }
    
            ProgressBar progressBar;
            WebClient webc;
            Queue<DownloadEntry> ToDownload = new Queue<DownloadEntry>();
    
            bool _canChange = true;
            public bool CanChange
            {
                get
                {
                    return _canChange;
                }
                set
                {
                    _canChange = value;
                    OnPropertyChanged("CanChange");
                }
            }
    
            #endregion
    
            public SkyWebClient(IEnumerable<DownloadEntry> downloadConfigs)
                :this(downloadConfigs, null)
            {
    
            }
    
            public SkyWebClient(IEnumerable<DownloadEntry> downloadConfigs, ProgressBar progressBar)
            {
                if (downloadConfigs == null)
                {
                    throw new ArgumentNullException("downloadConfigs");
                }
                foreach (DownloadEntry item in downloadConfigs)
                {
                    ToDownload.Enqueue(item);
                }
                this.webc = new WebClient();
                this.progressBar = progressBar;
                
                webc.DownloadFileCompleted += Webc_DownloadFileCompleted; //注册下载完成事件
                webc.DownloadProgressChanged += Webc_DownloadProgressChanged; //注册下载进度改变事件
            }
    
            public void Start()
            {
                if (ToDownload.Count == 0)
                {
                    Downloaded();
                    return;
                }
                if (CanChange)
                {
                    CanChange = false;
                    if (this.progressBar != null)
                    {
                        this.progressBar.Maximum = ToDownload.Count * 100;
                    }
                    StartCore();
                }
                else
                {
                    ToDownload.Clear();
                    webc.CancelAsync();
                    CanChange = true;
                    //this.progressBar.Value = 0;
                    //btnRunByWebClient.Text = "用 WebClient 开始下载";
                }
            }
    
            private void StartCore()
            {
                DownloadEntry next = ToDownload.Dequeue();
                webc.DownloadFileAsync(new Uri(next.Url), next.Path);
                OnWhenSingleDownloading(next);
            }
    
            private void DownloadNext()
            {
                if (ToDownload.Any())
                {
                    StartCore();
                    if (this.progressBar != null)
                    {
                        this.progressBar.Value = this.progressBar.Maximum - ((ToDownload.Count + 1) * 100);
                    }
                }
                else
                {
                    if (this.progressBar != null)
                    {
                        this.progressBar.Value = 0;
                    }
                    Downloaded();
                }
            }
    
            private void Downloaded()
            {
                CanChange = true;
                OnWhenAllDownloaded();
            }
    
            private void Webc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
            {
                if (e.Error != null && !e.Cancelled)
                {
                    OnWhenDownloadingError(e.Error);
                    CanChange = true;
                    //this.progressBar.Value = 0;
                }
                else
                {
                    DownloadNext();
                }
            }
    
            private void Webc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
            {
                if (this.progressBar != null)
                {
                    this.progressBar.Value = this.progressBar.Maximum - ((ToDownload.Count + 1) * 100) + e.ProgressPercentage;
                }
            }
        }

    2. Form1.cs

    在点击事件中,调用 SkyWebClient。

        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private List<int> GetDownloadIds()
            {
                List<int> ids = new List<int>(100);
                for (int i = 1; i <= 100; i++)
                {
                    ids.Add(i);
                }
                return ids;
            }
    
            private void WhenAllDownloading()
            {
                this.listBoxLog.Items.Insert(0, string.Format("当前时间:{0},准备开始下载...", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                //禁用按钮
                EnableOrDisableButtons(false);
            }
    
            private void EnableOrDisableButtons(bool enabled)
            {
                this.btnRunByHttpClient.Enabled = enabled;
                this.btnRunByWebClient.Enabled = enabled;
            }
    
            private void WhenSingleDownloaded(int id, bool singleDownloadSuccess)
            {
                this.listBoxLog.Items.Insert(0, string.Format("当前时间:{0},编号 {1} 下载 {2}!", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), id, singleDownloadSuccess));
            }
    
            private void WhenAllDownloaded()
            {
                this.listBoxLog.Items.Insert(0, string.Format("当前时间:{0},下载完毕!", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                //启用按钮
                EnableOrDisableButtons(true);
            }
    
            private async void btnRunByHttpClient_Click(object sender, EventArgs e)
            {
                SkyHttpClient skyHttpClient = new SkyHttpClient();
                try
                {
                    WhenAllDownloading();
                    foreach (var id in GetDownloadIds())
                    {
                        bool singleDownloadSuccess = await TaskDemo101.RunByHttpClient(skyHttpClient, id);
                        WhenSingleDownloaded(id, singleDownloadSuccess);
                    }
                    WhenAllDownloaded();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "Download Error!");
                }
            }
    
            private void btnRunByWebClient_Click(object sender, EventArgs e)
            {
                WhenAllDownloading();
                var ids = GetDownloadIds();
                List<DownloadEntry> downloadConfigs = new List<DownloadEntry>();
                Random rd = new Random();
                foreach (var id in ids)
                {
                    downloadConfigs.Add(new DownloadEntry(TaskDemo101.GetRandomUrl(rd), TaskDemo101.GetSavedFileFullName(), id));
                }
                SkyWebClient skyWebClient = new SkyWebClient(downloadConfigs, this.progressBar1);
                skyWebClient.WhenAllDownloaded += SkyWebClient_WhenAllDownloaded;
                skyWebClient.WhenSingleDownloading += SkyWebClient_WhenSingleDownloading;
                skyWebClient.WhenDownloadingError += SkyWebClient_WhenDownloadingError;
                skyWebClient.Start();
            }
    
            private void SkyWebClient_WhenDownloadingError(Exception ex)
            {
                MessageBox.Show("下载时出现错误: " + ex.Message);
            }
    
            private void SkyWebClient_WhenSingleDownloading(DownloadEntry current)
            {
                WhenSingleDownloaded((int)current.Data, true);
            }
    
            private void SkyWebClient_WhenAllDownloaded()
            {
                btnRunByWebClient.Text = "用 WebClient 开始下载";
                WhenAllDownloaded();
            }
    
            
        }

    3. 运行截图

    如图:

    4. 总结

    由于本下载采用依次来异步下载,虽然可以保证下载的文件的完整,但单位时间内效率不高,可能进度缓慢。且如果其中一个占用了较多的时间(比如:2分钟),那么整体的下载进度就会变慢。接下来,我会逐步优化它,敬请关注!

    谢谢浏览!

  • 相关阅读:
    SpringMVC 高级开发(异常页面处理,json传输数据,文件上传)
    SpringMVC中的Controller方法的(返回值/参数类型)
    SpringMVC的其他注解
    SpringMVC的整合,基于注解
    SpringMVC入门程序:helloWorld
    SpringMVC入门
    SpringAOP事务的实现
    仅需三步,即可在Vue项目中配置sass
    前端常用的设计模式
    call和apply的区别及其用法
  • 原文地址:https://www.cnblogs.com/Music/p/WebClient-DownloadFileAsync2.html
Copyright © 2011-2022 走看看