本次代码用于实现文件的并发下载。通过从一个文本文件(软件下载1.txt
)中读取软件下载链接,并将这些信息添加到一个ListView
控件中,同时开始多个文件的下载任务。
一.点击测试按钮实现读取下载链接
DownLoadFile dlf = new DownLoadFile();
private void btnTest_Click(object sender, EventArgs e)
{
string[] lines = File.ReadAllLines("软件下载1.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 = Path.GetFileName(path);
string dir = @"F:\test";
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();
}
1.成员变量
DownLoadFile dlf = new DownLoadFile();
: 创建一个DownLoadFile
类的对象dlf
,用于处理文件下载。不过需要注意的是,DownLoadFile
类的具体实现并没有在这段代码中给出。
2.事件处理器
-
private void btnTest_Click(object sender, EventArgs e)
: 当窗体上的一个按钮(可能是名为btnTest
的按钮)被点击时触发的方法。 -
读取文件: 使用
File.ReadAllLines("软件下载1.txt")
方法读取名为软件下载1.txt
的文本文件中的所有行,并将它们存储在lines
字符串数组中。 -
解析文件内容:遍历`lines`数组中的每一行。使用`Split`方法按`|`字符将每一行拆分成多个部分,并存储在`line`字符串数组中。检查`line`数组的长度是否为2,如果是,则认为该行包含有效的下载信息。
-
处理下载信息:使用`Uri.EscapeUriString`方法对下载链接进行转义处理(虽然在这里看起来有些多余,因为`path`只是作为文件名使用,而不是直接作为URI)。使`Path.GetFileName`方法从转义后的链接中提取文件名。设置下载目录为`F:\test`。创建一个新`ListViewItem`对象,并将相关信息(如文件名、状态等)添加到`listView1`控件中。 调用`dlf.AddDown`方法,将下载链接、目录、以及`ListViewItem`的索引等信息添加到`DownLoadFile`类的下载队列中。
-
开始下载:调用`dlf.StartDown`方法,开始下载队列中的所有文件。具体的下载逻辑应该在`DownLoadFile`类中实现。
总的来说,这个窗体的主要功能是读取一个包含下载链接的文本文件,将下载信息展示在ListView
控件中,并开始下载这些文件。
二 多线程下载处理以及更新UI来显示下载进度和状态
private void Form1_Load(object sender, EventArgs e)
{
dlf.ThreadNum = 3;//线程数,不设置默认为3
dlf.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();
}
SendMsgHander
方法是一个私有方法,它接收一个名为msg
的DownMsg
类型参数。这个方法根据msg
对象的Tag
属性(它应该是一个枚举类型DownStatus
的成员)来决定如何更新一个名为listView1
的列表视图控件(ListView)的项。
1.Start下载状态
- 如果
msg.Tag
是DownStatus.Start
,则更新listView1
中指定Id
的项的第9个子项(通常索引从0开始,但这里假设从1开始计数)为“开始下载”,并更新第8个子项为当前时间。 - 使用了
Invoke
方法确保UI更新在UI线程上执行,这是必要的,因为该方法可能在一个非UI线程中被调用
2.获取文件长度状态
- 如果
msg.Tag
是DownStatus.GetLength
,则更新listView1
中指定Id
的项的第4个子项为msg.LengthInfo
(可能是文件的总长度或大小),并更新第9个子项为“连接成功”。 - 同样,使用
Invoke
确保UI更新在正确的线程上执行。
3.下载中或下载完成状态
- 如果
msg.Tag
是DownStatus.End
或DownStatus.DownLoad
,则更新listView1
中指定Id
的项的多个子项,包括文件大小、下载进度、下载速度、剩余时间,以及下载状态(下载中或下载完成)。 - 这里的代码原本有嵌套的
Invoke
调用,但经过修改后已经简化为单个Invoke
。 Application.DoEvents()
的调用被移除了,因为它可能导致不可预测的行为,通常不推荐在UI更新后使用。
DownStatus.End
和DownStatus.DownLoad
:更新多个子项来显示下载的状态、进度、速度、剩余时间等信息,并更新第9个子项为“下载中”或“下载完成”。
4.错误状态
- 如果
msg.Tag
是DownStatus.Error
(尽管代码段中没有完整展示这个case
的处理),我们可以假设它会更新listView1
中指定Id
的项的状态为错误,并可能显示一个错误消息。 - 同样,使用了
Invoke
来确保UI更新在UI线程上执行。
完整代码如下,仅供参考:
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("软件下载1.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 = Path.GetFileName(path);
string dir = @"F:\test";
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;//线程数,不设置默认为3
dlf.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;
}
}
}
}
windows窗口界面如下: