一个简单的利用 WebClient 异步下载的示例(一)

继上一篇文章 一个简单的利用 HttpClient 异步下载的示例 ,我们知道不管是 HttpClient,还算 WebClient,都不建议每次调用都 new HttpClient,或 new WebClient,而应该尽量重复对象,可以把一个 WebClient(或 HttpClient)理解成一个浏览器,不能没打开一个页面以后,就销毁它,再重新创建一个,这样会有性能损失,而建议一个线程共用一个 WebClient(或 HttpClient)。这一次,我们利用 WebClient 来实现异步下载,这一次,我们增加一个进度条来显示进度。

直接提代码了:

1. TaskDemo101

优化后的 TaskDemo101 类:

     public static class TaskDemo101
    {
        public static string GetRandomUrl()
        {
            string url1 = "http://www.xxx.me/Uploads/image/20130129/2013012920080761761.jpg";
            string url2 = "http://www.xxx.me/Uploads/image/20121222/20121222230686278627.jpg";
            string url3 = "http://www.xxx.me/Uploads/image/20120606/20120606222018461846.jpg";
            string url4 = "http://www.xxx.me/Uploads/image/20121205/20121205224383848384.jpg";
            string url5 = "http://www.xxx.me/Uploads/image/20121205/20121205224251845184.jpg";

            string resultUrl;
            int randomNum = new Random().Next(1, 6);
            switch (randomNum)
            {
                case 1: resultUrl = url1; break;
                case 2: resultUrl = url2; break;
                case 3: resultUrl = url3; break;
                case 4: resultUrl = url4; break;
                case 5: resultUrl = url5; break;
                default: throw new Exception("");
            }
            return resultUrl;
        }

        public static string GetSavedFileFullName()
        {
            string targetFolderDestination = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "downloads\images\");
            try
            {
                Directory.CreateDirectory(targetFolderDestination);
            }
            catch (Exception)
            {
                Console.WriteLine("创建文件夹失败!");
            }
            string targetFileDestination = Path.Combine(targetFolderDestination, string.Format("img_{0}.png", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")));
            return targetFileDestination;
        }

        public static async Task<bool> RunByHttpClient(SkyHttpClient skyHttpClient, int id)
        {
            var task = skyHttpClient.DownloadImage(GetRandomUrl());
            return await task.ContinueWith<bool>(t => {
                File.WriteAllBytes(GetSavedFileFullName(), t.Result);
                return true;
            });
        }

        public static void RunByWebClient(WebClient webClient, int id)
        {
            webClient.DownloadFileAsync(new Uri(GetRandomUrl()), GetSavedFileFullName());
        }
    }

2. Form1 

这一次我们的 Form1 实现了 INotifyPropertyChanged 接口

    public partial class Form1 : Form, INotifyPropertyChanged
    {
        #region 字段、属性

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
            }
        }
        WebClient webc = new WebClient();
        bool _canChange = true;
        public bool CanChange
        {
            get
            {
                return _canChange;
            }
            set
            {
                _canChange = value;
                OnPropertyChanged("CanChange");
            }
        }

        #endregion

        public Form1()
        {
            InitializeComponent();
            webc.DownloadFileCompleted += Webc_DownloadFileCompleted; //注册下载完成事件
            webc.DownloadProgressChanged += Webc_DownloadProgressChanged; //注册下载进度改变事件
        }

        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)
        {
            if (CanChange)
            {
                WhenAllDownloading();
                CanChange = false;

                ToDownload.Clear();
                foreach (var id in GetDownloadIds())
                {
                    ToDownload.Enqueue(id);
                }

                progressBar1.Maximum = ToDownload.Count * 100;
                btnRunByWebClient.Text = "用 WebClient 暂停下载";

                int firstId = ToDownload.Dequeue();
                TaskDemo101.RunByWebClient(webc, firstId);
                WhenSingleDownloaded(firstId, true);
            }
            else
            {
                ToDownload.Clear();
                webc.CancelAsync();
                CanChange = true;
                progressBar1.Value = 0;
                btnRunByWebClient.Text = "用 WebClient 开始下载";
            }
        }

        private void Webc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null && !e.Cancelled)
            {
                MessageBox.Show("下载时出现错误: " + e.Error.Message);
                CanChange = true;
                progressBar1.Value = 0;
            }
            else
            {
                DownloadNext();
            }
        }

        private void Webc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            progressBar1.Value = progressBar1.Maximum - ((ToDownload.Count + 1) * 100) + e.ProgressPercentage;
        }

        Queue<int> ToDownload = new Queue<int>();

        private void DownloadNext()
        {
            if (ToDownload.Any())
            {
                int nextId = ToDownload.Dequeue();
                TaskDemo101.RunByWebClient(webc, nextId);
                WhenSingleDownloaded(nextId, true);
                progressBar1.Value = progressBar1.Maximum - ((ToDownload.Count + 1) * 100);
            }
            else
            {
                MessageBox.Show("全部下载完成");
                CanChange = true;
                progressBar1.Value = 0;
                btnRunByWebClient.Text = "用 WebClient 开始下载";
                WhenAllDownloaded();
            }
        }
    }

3. 运行截图

如图:

下载完成以后:

谢谢浏览!

原文地址:https://www.cnblogs.com/Music/p/WebClient-DownloadFileAsync.html