目录
目录
1.作业内容
2.作业要求
3.主要思路
1)窗体和组件初始化
2)下载管理器实例化
3)按钮点击事件处理
4)窗体加载事件处理
5)下载消息处理
4.主要难点
1)多线程管理:
2) UI更新:
3) 错误处理:
4) 资源管理:
5) 用户体验:
5.不足及改进
参考:
6.代码展示
代码仓库
7.运行结果
1.作业内容
通过c#实现一个基本的多线程文件下载器,用于从一个文本文件中读取下载链接,并启动多线程下载,可以在Windows窗体应用程序中使用。同时,也可以更新UI显示文件下载内容和进度情况。
- 并发下载
- 网络连接
- ...
2.作业要求
请以博客方式提交作业,博客内容需要对代码行进行讲解,阐述设计的主要思路与难点。 | √ |
请注意,如果想达到博客网站如csdn的优质博文的质量分,需要对博客进行详细描述。 | √ |
提交方式为提交博客发布地址,并附上本博文的质量分。 | √ |
3.主要思路
由于核心代码已有,本人只是在此基础上进行修改,理解其核心原理和过程
1)窗体和组件初始化
- `Form1()` 构造函数:初始化窗体,并调用 `InitializeComponent()` 方法,后者由WinForms设计器自动生成,用于设置窗体上的控件。
public Form1(){InitializeComponent();}
2)下载管理器实例化
- `DownLoadFile dlf = new DownLoadFile();`:创建 `DownLoadFile` 类的实例,该类负责管理下载任务。
DownLoadFile dlf = new DownLoadFile();
3)按钮点击事件处理
- - `btnTest_Click`:当用户点击界面上的某个按钮时触发此事件。
- - 读取文本文件 `"下载文件.txt"` 中的每一行,每行包含一个文件名和一个URL,它们通过 `|` 分隔。
- - 对每行进行分割,提取文件名和URL。
- - 使用 `Uri.EscapeUriString` 对URL进行编码,确保URL在传输过程中的安全性。
- - 将文件下载存放路径设置为 `dir` 变量。
- - 在列表视图 `listView1` 中为每个下载任务添加一个项,并设置初始状态。
- - 调用 `dlf.AddDown` 方法添加下载任务,传入下载链接、存放目录、任务索引和索引的字符串表示。
- - 调用 `dlf.StartDown` 开始下载任务。
private void btnTest_Click(object sender, EventArgs e){string[] lines = File.ReadAllLines("D:\\table\\作业\\windows\\作业\\作业三\\DownLoadFile\\下载文件.txt");for (int i = 0; i < lines.Length; i++){string[] line = lines[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);if (line.Length == 2){string path = Uri.EscapeUriString(line[1]);string filename = line[0];//string filename = Path.GetFileName(path);string dir = @"D:\\table\作业\windows\作业\作业三\DownLoadFile\文件下载存放处";ListViewItem item = listView1.Items.Add(new ListViewItem(new string[] { (listView1.Items.Count + 1).ToString(), filename, "0", "0", "0%", "0", "0", DateTime.Now.ToString(), "等待中", line[1] }));int id = item.Index;dlf.AddDown(path, dir, id, id.ToString());}}dlf.StartDown();}
4)窗体加载事件处理
- - `Form1_Load`:在窗体加载时设置下载器的线程数,并注册下载过程中的消息处理事件 `SendMsgHander`。
private void Form1_Load(object sender, EventArgs e){dlf.ThreadNum = 3;//线程数,不设置默认为3dlf.doSendMsg += SendMsgHander;//下载过程处理事件}
5)下载消息处理
- - `SendMsgHander`:根据下载过程中的不同状态更新UI。
- - `DownStatus.Start`:下载开始时更新状态。
- - `DownStatus.GetLength`:获取文件长度时更新状态。
- - `DownStatus.End` 和 `DownStatus.DownLoad`:下载过程中和下载结束时更新进度、速度和剩余时间。
- - `DownStatus.Error`:下载出错时更新错误信息。
private void SendMsgHander(DownMsg msg){switch (msg.Tag){case DownStatus.Start:this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[8].Text = "开始下载";listView1.Items[msg.Id].SubItems[7].Text = DateTime.Now.ToString();});break;case DownStatus.GetLength:this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[3].Text = msg.LengthInfo;listView1.Items[msg.Id].SubItems[8].Text = "连接成功";});break;case DownStatus.End:case DownStatus.DownLoad:this.Invoke(new MethodInvoker(() =>{this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[2].Text = msg.SizeInfo;listView1.Items[msg.Id].SubItems[4].Text = msg.Progress.ToString() + "%";listView1.Items[msg.Id].SubItems[5].Text = msg.SpeedInfo;listView1.Items[msg.Id].SubItems[6].Text = msg.SurplusInfo;if (msg.Tag == DownStatus.DownLoad){listView1.Items[msg.Id].SubItems[8].Text = "下载中";}else{listView1.Items[msg.Id].SubItems[8].Text = "下载完成";}Application.DoEvents();});}));break;case DownStatus.Error:this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[6].Text = "失败";listView1.Items[msg.Id].SubItems[8].Text = msg.ErrMessage;Application.DoEvents();});break;}}
4.主要难点
1)多线程管理:
正确地管理多个下载线程,确保它们不会相互干扰,同时高效地利用系统资源。
2) UI更新:
在多线程环境中安全地更新UI,因为UI控件只能通过创建它们的线程(通常是主线程)进行操作。这里使用了 `Invoke` 方法来确保在主线程上更新UI。
3) 错误处理:
在下载过程中可能会遇到各种错误,如网络问题、文件写入权限问题等。我们需要能够处理这些错误,并给用户适当的反馈。
4) 资源管理:
确保所有资源(如文件流、网络连接)在使用后都能正确关闭和释放,防止资源泄露。
5) 用户体验:
提供清晰的进度指示和错误信息,使用户能够了解下载状态和问题。
5.不足及改进
对下载文件的命名进行优化,下载生成文件具有良好的可阅读性,同时能对其后缀进行自动添加。
能否由用户控制下载哪几个文件,而不是全部下载了。
参考:
https://www.cnblogs.com/jianzhan/p/7137485.html
6.代码展示
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Gac;namespace Demo
{public partial class Form1 : Form{public Form1(){InitializeComponent();}DownLoadFile dlf = new DownLoadFile();private void btnTest_Click(object sender, EventArgs e){string[] lines = File.ReadAllLines("D:\\table\\作业\\windows\\作业\\作业三\\DownLoadFile\\下载文件.txt");for (int i = 0; i < lines.Length; i++){string[] line = lines[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);if (line.Length == 2){string path = Uri.EscapeUriString(line[1]);string filename = line[0];//string filename = Path.GetFileName(path);string dir = @"D:\\table\作业\windows\作业\作业三\DownLoadFile\文件下载存放处";ListViewItem item = listView1.Items.Add(new ListViewItem(new string[] { (listView1.Items.Count + 1).ToString(), filename, "0", "0", "0%", "0", "0", DateTime.Now.ToString(), "等待中", line[1] }));int id = item.Index;dlf.AddDown(path, dir, id, id.ToString());}}dlf.StartDown();}private void Form1_Load(object sender, EventArgs e){dlf.ThreadNum = 3;//线程数,不设置默认为3dlf.doSendMsg += SendMsgHander;//下载过程处理事件}private void SendMsgHander(DownMsg msg){switch (msg.Tag){case DownStatus.Start:this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[8].Text = "开始下载";listView1.Items[msg.Id].SubItems[7].Text = DateTime.Now.ToString();});break;case DownStatus.GetLength:this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[3].Text = msg.LengthInfo;listView1.Items[msg.Id].SubItems[8].Text = "连接成功";});break;case DownStatus.End:case DownStatus.DownLoad:this.Invoke(new MethodInvoker(() =>{this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[2].Text = msg.SizeInfo;listView1.Items[msg.Id].SubItems[4].Text = msg.Progress.ToString() + "%";listView1.Items[msg.Id].SubItems[5].Text = msg.SpeedInfo;listView1.Items[msg.Id].SubItems[6].Text = msg.SurplusInfo;if (msg.Tag == DownStatus.DownLoad){listView1.Items[msg.Id].SubItems[8].Text = "下载中";}else{listView1.Items[msg.Id].SubItems[8].Text = "下载完成";}Application.DoEvents();});}));break;case DownStatus.Error:this.Invoke((MethodInvoker)delegate (){listView1.Items[msg.Id].SubItems[6].Text = "失败";listView1.Items[msg.Id].SubItems[8].Text = msg.ErrMessage;Application.DoEvents();});break;}}}
}
代码仓库
https://github.com/Tiansky9/sky.git