线程机制(避免卡屏),异步下载文件。
我做网站的监控,WebClient.DownloadFile这个方法是我经常用到的,必要的时候肯定是要从网上下载些什么(WebRequest 也可以下载网络文件,不妨搜下,不过WebClient.DownloadFile使用更简单)。
今天简单的演示下WebClient.DownloadFileAsync的使用,刚刚写好的实例,有问题你拍我。
解释什么的都不需要了吧。这里面应用了线程机制,异步调用。wo先展示代码,在把一些关键点放置到后面,并给一些修改建议(设计器生成代码在下,可以不用看,只需要复制粘贴使用)。
测试中用到的网络文件(随机抽取.exe,.rar,.zip),都是无害的,请放心测试:
http://dl1sw.baidu.com/client/9h162/fzjqd.exe
http://sq.onlinedown.net/down/sgbs.rar
http://zj.down.chinaz.com/201408/bdswxt_v1.0.zip
http://zj.down.chinaz.com/201408/zyzfwxt_v1.1.zip
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net; using System.Threading; using System.IO; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); } static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "error.log", DateTime.Now.ToString() + "\t" + e.ExceptionObject.ToString() + Environment.NewLine); } /// <summary> /// 文件总数 /// </summary> int _totalFile = 0; /// <summary> /// 已下载文件 /// </summary> int _loadFile = 0; private void button1_Click(object sender, EventArgs e) {//Run string richText = richTextBox1.Text; if (string.IsNullOrEmpty(richText)) { MessageBox.Show("请在文本框中输入需要下载的网络文件"); } Thread thread = new Thread(new ThreadStart(() => createWebClient(richText))); thread.Start(); } //WebClient webClient = null; private void createWebClient(string richText) { string[] array = richText.Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); _totalFile = array.Length; foreach (string item in array) { WebClient webClient = new WebClient(); webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged); webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted); string fileName = AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.ToFileTimeUtc() + item.Substring(item.LastIndexOf('/') + 1); webClient.DownloadFileAsync(new Uri(item), fileName); } } private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) { this.Invoke(new MethodInvoker(delegate { this.progressBar2.Value = e.ProgressPercentage; this.label2.Text = string.Format("正在下载文件,完成进度{0}% {1}/{2}(字节)" ,e.ProgressPercentage , e.BytesReceived , e.TotalBytesToReceive); })); } private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) { _loadFile++; int percent = (int)(100.0 * _loadFile / _totalFile); this.Invoke(new MethodInvoker(delegate { this.progressBar1.Value = percent; this.label1.Text = string.Format("已完成文件下载{0}% {1}/{2}(文件个数)" , percent , _loadFile , _totalFile); })); if (sender is WebClient) { ((WebClient)sender).CancelAsync(); ((WebClient)sender).Dispose(); } } private System.ComponentModel.IContainer components = null; protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } private void InitializeComponent() { this.progressBar1 = new System.Windows.Forms.ProgressBar(); this.progressBar2 = new System.Windows.Forms.ProgressBar(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.richTextBox1 = new System.Windows.Forms.RichTextBox(); this.button1 = new System.Windows.Forms.Button(); this.SuspendLayout(); // // progressBar1 // this.progressBar1.Location = new System.Drawing.Point(81, 160); this.progressBar1.Name = "progressBar1"; this.progressBar1.Size = new System.Drawing.Size(330, 12); this.progressBar1.TabIndex = 0; // // progressBar2 // this.progressBar2.Location = new System.Drawing.Point(81, 224); this.progressBar2.Name = "progressBar2"; this.progressBar2.Size = new System.Drawing.Size(330, 12); this.progressBar2.TabIndex = 1; // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(59, 187); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(41, 12); this.label1.TabIndex = 2; this.label1.Text = "label1"; // // label2 // this.label2.AutoSize = true; this.label2.Location = new System.Drawing.Point(59, 252); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(41, 12); this.label2.TabIndex = 3; this.label2.Text = "label2"; // // label3 // this.label3.AutoSize = true; this.label3.Location = new System.Drawing.Point(12, 160); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(65, 12); this.label3.TabIndex = 4; this.label3.Text = "总 进 度:"; // // label4 // this.label4.AutoSize = true; this.label4.Location = new System.Drawing.Point(12, 224); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(65, 12); this.label4.TabIndex = 5; this.label4.Text = "当前进度:"; // // richTextBox1 // this.richTextBox1.Location = new System.Drawing.Point(14, 12); this.richTextBox1.Name = "richTextBox1"; this.richTextBox1.Size = new System.Drawing.Size(397, 131); this.richTextBox1.TabIndex = 6; this.richTextBox1.Text = ""; // // button1 // this.button1.Location = new System.Drawing.Point(150, 280); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 7; this.button1.Text = "Run"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(423, 315); this.Controls.Add(this.button1); this.Controls.Add(this.richTextBox1); this.Controls.Add(this.label4); this.Controls.Add(this.label3); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.Controls.Add(this.progressBar2); this.Controls.Add(this.progressBar1); this.MaximumSize = new System.Drawing.Size(439, 353); this.MinimumSize = new System.Drawing.Size(439, 353); this.Name = "Form1"; this.Text = "WebClient下载实现实例"; this.ResumeLayout(false); this.PerformLayout(); } private System.Windows.Forms.ProgressBar progressBar1; private System.Windows.Forms.ProgressBar progressBar2; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; private System.Windows.Forms.Label label3; private System.Windows.Forms.Label label4; private System.Windows.Forms.RichTextBox richTextBox1; private System.Windows.Forms.Button button1; } }
大致看了一下,貌似就以下几句需要新手斟酌,大神请绕行。
第一句: this.Invoke(new MethodInvoker(delegate {
第二句:Thread thread = new Thread(new ThreadStart(() => createWebClient(richText)));
第三句:if (sender is WebClient)
第一句是关键的一句,不再创建控件的线程中调用/修改控件的属性值(Text),会报异常,为什么这么用就OK了?
第二句,第三句就简单了,不提示了,不会了找度度。
本程序可以添加的功能,添加一个Stop按钮,终断下载(请不要嗤之以鼻,在创建窗体的线程里操作new Thread让其立即终断下载,还是有点深度)