C# 多线程多文件批量下载---子线程中更新UI 实例
代码1:
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("华军软件.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 = @"D:\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();
//"http://localhost:1829/Rource/585615db-8f36-4c25-bca1-3a4b7b9953b4.jpg",
//"http://localhost:1829/Rource/2287833a-eb1d-4365-b003-9b43758b78da.gif"
string[] lines = {
"http://localhost:1829/Rource/585615db-8f36-4c25-bca1-3a4b7b9953b4.jpg",
"http://localhost:1829/Rource/2287833a-eb1d-4365-b003-9b43758b78da.gif" };
for (int i = 0; i < lines.Length; i++)
{
//string[] line = lines[i].Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
//if (lines.Length == 2)
//{
string path = lines[i];
string filename = Path.GetFileName(path);
string dir = @"C:\Users\Administrator\Desktop";
ListViewItem item = listView1.Items.Add(new ListViewItem(new string[] { (listView1.Items.Count + 1).ToString(), filename, "0", "0", "0%", "0", "0", DateTime.Now.ToString(), "等待中", lines[i] }));
int id = item.Index;
dlf.AddDown(path, dir, id, filename);
//}
}
dlf.StartDown();
}
private void Form1_Load(object sender, EventArgs e)
{
dlf.ThreadNum = 3;//线程数,不设置默认为3
dlf.doSendMsg += SendMsgHander;//下载过程处理事件
}
private void Form1_Layout(object sender, LayoutEventArgs e)
{
throw new NotImplementedException();
}
private void SendMsgHander(DownLoadMessage msg)
{
switch (msg.Tag)
{
case DownLoadStatus.Start:
this.Invoke((MethodInvoker)delegate ()
{
listView1.Items[msg.Id].SubItems[8].Text = "开始下载";
listView1.Items[msg.Id].SubItems[7].Text = DateTime.Now.ToString();
});
break;
case DownLoadStatus.GetLength:
this.Invoke((MethodInvoker)delegate ()
{
listView1.Items[msg.Id].SubItems[3].Text = msg.LengthInfo;
listView1.Items[msg.Id].SubItems[8].Text = "连接成功";
});
break;
case DownLoadStatus.End:
case DownLoadStatus.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 == DownLoadStatus.DownLoad)
{
listView1.Items[msg.Id].SubItems[8].Text = "下载中";
}
else
{
listView1.Items[msg.Id].SubItems[8].Text = "下载完成";
}
Application.DoEvents();
});
}));
break;
case DownLoadStatus.Error:
this.Invoke((MethodInvoker)delegate ()
{
listView1.Items[msg.Id].SubItems[6].Text = "失败";
listView1.Items[msg.Id].SubItems[8].Text = msg.ErrMessage;
Application.DoEvents();
});
break;
}
}
}
}
代码2:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace Gac
{
public class DownLoadFile
{
public int ThreadNum = 3;
List<Thread> list = new List<Thread>();
public DownLoadFile()
{
doSendMsg += Change;
}
private void Change(DownLoadMessage msg)
{
if (msg.Tag == DownLoadStatus.Error || msg.Tag == DownLoadStatus.End)
{
StartDown(1);
}
}
public void AddDown(string downUrl, string dir, int id = 0, string fileName = "")
{
Thread tsk = new Thread(() =>
{
Download(downUrl, dir, fileName, id);
});
list.Add(tsk);
}
public void StartDown(int startNum = 3)
{
for (int i2 = 0; i2 < startNum; i2++)
{
lock (list)
{
for (int i = 0; i < list.Count; i++)
{
if (list[i].ThreadState == ThreadState.Unstarted || list[i].ThreadState == ThreadState.Suspended)
{
list[i].Start();
break;
}
}
}
}
}
public delegate void dlgSendMsg(DownLoadMessage msg);
public event dlgSendMsg doSendMsg;
//public event doSendMsg;
//public dlgSendMsg doSendMsg = null;
private void Download(string path, string dir, string filename, int id = 0)
{
try
{
DownLoadMessage msg = new DownLoadMessage();
msg.Id = id;
msg.Tag = 0;
doSendMsg(msg);
FileDownloader loader = new FileDownloader(path, dir, filename, 4);
loader.data.Clear();
msg.Tag = DownLoadStatus.Start;
msg.Length = (int)loader.getFileSize(); ;
doSendMsg(msg);
DownloadProgressListener linstenter = new DownloadProgressListener(msg);
linstenter.doSendMsg = new DownloadProgressListener.dlgSendMsg(doSendMsg);
loader.download(linstenter);
}
catch (Exception ex)
{
DownLoadMessage msg = new DownLoadMessage();
msg.Id = id;
msg.Length = 0;
msg.Tag = DownLoadStatus.Error;
msg.ErrMessage = ex.Message;
doSendMsg(msg);
Console.WriteLine(ex.Message);
}
}
}
}
代码3:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;
using System.Net;
namespace Gac
{
/// <summary>
/// 多个线程分块下载一个文件
/// </summary>
public class FileDownloader
{
/// <summary>
/// 已下载文件长度
/// </summary>
private long downloadSize = 0;
/// <summary>
/// 原始文件长度
/// </summary>
private long fileSize = 0;
/// <summary>
/// 线程数
/// </summary>
private DownloadThread[] threads;
/// <summary>
/// 本地保存文件
/// </summary>
private string saveFilePath;
/// <summary>
/// 缓存各线程下载的长度
/// </summary>
public Dictionary<int, long> data = new Dictionary<int, long>();
/// <summary>
/// 分块,每条线程下载的长度,每一块的大小
/// </summary>
private long block;
/// <summary>
/// 下载路径
/// </summary>
private String downloadUrl;
/// <summary>
/// 获取线程数
/// </summary>
/// <returns> 获取线程数</returns>
public int getThreadSize()
{
return threads.Length;
}
/// <summary>
/// 获取文件大小
/// </summary>
/// <returns>获取文件大小</returns>
public long getFileSize()
{
return fileSize;
}
/// <summary>
/// 累计已下载大小
/// </summary>
/// <param name="size">累计已下载大小</param>
public void append(long size)
{
lock (this) //锁定同步
{
downloadSize += size;
}
}
/// <summary>
/// 更新指定线程最后下载的位置
/// </summary>
/// <param name="threadId">threadId 线程id</param>
/// <param name="pos">最后下载的位置</param>
public void update(int threadId, long pos)
{
if (data.ContainsKey(threadId))
{
this.data[threadId] = pos;
}
else
{
this.data.Add(threadId, pos);
}
}
/// <summary>
/// 构造函数,构建下载准备,获取文件大小
/// </summary>
/// <param name="downloadUrl">下载路径</param>
/// <param name="fileSaveDir"> 文件保存目录</param>
/// <param name="threadNum">下载线程数</param>
public FileDownloader(string downloadUrl, string fileSaveDir, string filename = "", int threadNum = 3)
{
try
{
//if (string.IsNullOrEmpty(filename))
//{
// filename = Uri.UnescapeDataString(Path.GetFileName(downloadUrl));//获取文件名称 uri 解码中文字符
//}
if (string.IsNullOrEmpty(filename))
{
filename = Path.GetFileName(downloadUrl);
}
//构建http 请求
this.downloadUrl = downloadUrl;
if (!Directory.Exists(fileSaveDir)) Directory.CreateDirectory(fileSaveDir);
this.threads = new DownloadThread[threadNum];
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(downloadUrl);
request.Referer = downloadUrl.ToString();
request.Method = "GET";
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 2.0.1124)";
request.ContentType = "application/octet-stream";
request.Accept = "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*";
request.Timeout = 20 * 1000;
request.AllowAutoRedirect = true;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode == HttpStatusCode.OK)
{
Stream tempStream = response.GetResponseStream();
//开辟内存空间
byte[] tempbuffer = new byte[512];
//获取文件读取到的长度
long templength = 0;
//获取服务端的下载文件的大小
long httpContentLength = 0;
while ((templength = tempStream.Read(tempbuffer, 0, 512)) > 0)
{
httpContentLength += templength;
}
tempStream.Close();
this.fileSize = httpContentLength;//根据响应获取文件大小
//this.fileSize = response.ContentLength;//根据响应获取文件大小
if (this.fileSize <= 0)
throw new Exception("获取文件大小失败");
if (filename.Length == 0)
throw new Exception("获取文件名失败");
this.saveFilePath = Path.Combine(fileSaveDir, filename); //构建保存文件
//计算每条线程下载的数据长度
this.block = (this.fileSize % this.threads.Length) == 0 ? this.fileSize / this.threads.Length : this.fileSize / this.threads.Length + 1;
}
else
{
throw new Exception("服务器返回状态失败,StatusCode:" + response.StatusCode);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw new Exception("无法连接下载地址");
}
}
/// <summary>
/// 开始下载文件
/// </summary>
/// <param name="listener">监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null</param>
/// <returns>已下载文件大小</returns>
public long download(IDownloadProgressListener listener)
{
try
{
using (FileStream fstream = new FileStream(this.saveFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (this.fileSize > 0)
fstream.SetLength(this.fileSize);
fstream.Close();
}
if (this.data.Count != this.threads.Length)
{
this.data.Clear();
for (int i = 0; i < this.threads.Length; i++)
{
this.data.Add(i + 1, 0);//初始化每条线程已经下载的数据长度为0
}
}
for (int i = 0; i < this.threads.Length; i++)
{
//开启线程进行下载
long downLength = this.data[i + 1];
if (downLength < this.block && this.downloadSize < this.fileSize)
{
//判断线程是否已经完成下载,否则继续下载
Console.WriteLine("threads " + i.ToString() + ",下载块" + this.block.ToString() + " " + this.data[i + 1].ToString() + " " + downloadSize.ToString());
this.threads[i] = new DownloadThread(this, downloadUrl, this.saveFilePath, this.block, this.data[i + 1], i + 1);
this.threads[i].ThreadRun();
}
else
{
this.threads[i] = null;
}
Thread.Sleep(1000);
}
bool notFinish = true;//下载未完成
while (notFinish)
{
// 循环判断所有线程是否完成下载
//Thread.Sleep(1000);
notFinish = false;//假定全部线程下载完成
for (int i = 0; i < this.threads.Length; i++)
{
if (this.threads[i] != null && !this.threads[i].isFinish())//如果发现线程未完成下载
{
notFinish = true;//设置标志为下载没有完成
if (this.threads[i].getDownLength() == -1)//如果下载失败,再重新下载
{
this.threads[i] = new DownloadThread(this, downloadUrl, this.saveFilePath, this.block, this.data[i + 1], i + 1);
this.threads[i].ThreadRun();
}
}
}
if (listener != null)
{
listener.OnDownloadSize(this.downloadSize);//通知目前已经下载完成的数据长度
Console.WriteLine(this.downloadSize);
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw new Exception("下载文件失败");
}
return this.downloadSize;
}
}
}
代码4:
using System;
using System.Collections.Generic;
using System.Text;
namespace Gac
{
public class DownloadProgressListener : IDownloadProgressListener
{
DownLoadMessage downMsg = null;
public delegate void dlgSendMsg(DownLoadMessage msg);
public dlgSendMsg doSendMsg = null;
public DownloadProgressListener(DownLoadMessage downmsg)
{
this.downMsg = downmsg;
//this.id = id;
//this.Length = Length;
}
public void OnDownloadSize(long size)
{
if (downMsg == null)
{
DownLoadMessage downMsg = new DownLoadMessage();
}
//下载速度
if (downMsg.Size == 0)
{
downMsg.Speed = size;
}
else
{
downMsg.Speed = (float)(size - downMsg.Size);
}
if (downMsg.Speed == 0)
{
downMsg.Surplus = -1;
downMsg.SurplusInfo = "未知";
}
else
{
downMsg.Surplus = ((downMsg.Length - downMsg.Size) / downMsg.Speed);
}
downMsg.Size = size; //下载总量
if (size == downMsg.Length)
{
//下载完成
downMsg.Tag = DownLoadStatus.End;
downMsg.SpeedInfo = "0 K";
downMsg.SurplusInfo = "已完成";
}
else
{
//下载中
downMsg.Tag = DownLoadStatus.DownLoad;
}
doSendMsg?.Invoke(downMsg);//通知具体调用者下载进度
}
}
public enum DownLoadStatus
{
Start,
GetLength,
DownLoad,
End,
Error
}
public class DownLoadMessage
{
private int _Length = 0;
private string _LengthInfo = "";
private int _Id = 0;
private DownLoadStatus _Tag = 0;
private long _Size = 0;
private string _SizeInfo = "";
private float _Speed = 0;
private float _Surplus = 0;
private string _SurplusInfo = "";
private string _ErrMessage = "";
private string _SpeedInfo = "";
private double _Progress = 0;
public int Length
{
get
{
return _Length;
}
set
{
_Length = value;
LengthInfo = GetFileSize(value);
}
}
public int Id
{
get
{
return _Id;
}
set
{
_Id = value;
}
}
public DownLoadStatus Tag
{
get
{
return _Tag;
}
set
{
_Tag = value;
}
}
public long Size
{
get
{
return _Size;
}
set
{
_Size = value;
SizeInfo = GetFileSize(value);
if (Length >= value)
{
Progress = Math.Round((double)value / Length * 100, 2);
}
else
{
Progress = -1;
}
}
}
public float Speed
{
get
{
return _Speed;
}
set
{
_Speed = value;
SpeedInfo = GetFileSize(value);
}
}
public string SpeedInfo
{
get
{
return _SpeedInfo;
}
set
{
_SpeedInfo = value;
}
}
public float Surplus
{
get
{
return _Surplus;
}
set
{
_Surplus = value;
if (value > 0)
{
SurplusInfo = GetDateName((int)Math.Round(value, 0));
}
}
}
public string ErrMessage
{
get
{
return _ErrMessage;
}
set
{
_ErrMessage = value;
}
}
public string SizeInfo
{
get
{
return _SizeInfo;
}
set
{
_SizeInfo = value;
}
}
public string LengthInfo
{
get
{
return _LengthInfo;
}
set
{
_LengthInfo = value;
}
}
public double Progress
{
get
{
return _Progress;
}
set
{
_Progress = value;
}
}
public string SurplusInfo
{
get
{
return _SurplusInfo;
}
set
{
_SurplusInfo = value;
}
}
private string GetFileSize(float Len)
{
float temp = Len;
string[] sizes = { "B", "KB", "MB", "GB" };
int order = 0;
while (temp >= 1024 && order + 1 < sizes.Length)
{
order++;
temp = temp / 1024;
}
return String.Format("{0:0.##} {1}", temp, sizes[order]);
}
private string GetDateName(int Second)
{
float temp = Second;
string suf = "秒";
if (Second > 60)
{
suf = "分钟";
temp = temp / 60;
if (Second > 60)
{
suf = "小时";
temp = temp / 60;
if (Second > 24)
{
suf = "天";
temp = temp / 24;
if (Second > 30)
{
suf = "月";
temp = temp / 30;
if (Second > 12)
{
suf = "年";
temp = temp / 12;
}
}
}
}
}
return String.Format("{0:0} {1}", temp, suf);
}
}
}
代码5:
using System;
using System.Collections.Generic;
using System.Text;
namespace Gac
{
public interface IDownloadProgressListener
{
void OnDownloadSize(long size);
}
}
原文链接:http://www.cnblogs.com/jianzhan/p/7137485.html
C# 多线程多文件批量下载---子线程中更新UI 实例的更多相关文章
- Android多线程之(一)View.post()源码分析——在子线程中更新UI
提起View.post(),相信不少童鞋一点都不陌生,它用得最多的有两个功能,使用简便而且实用: 1)在子线程中更新UI.从子线程中切换到主线程更新UI,不需要额外new一个Handler实例来实现. ...
- 使用Handler在子线程中更新UI
Android规定仅仅能在主线程中更新UI.假设在子线程中更新UI 的话会提演示样例如以下错误:Only the original thread that created a view hierach ...
- android 不能在子线程中更新ui的讨论和分析
问题描写叙述 做过android开发基本都遇见过 ViewRootImpl$CalledFromWrongThreadException,上网一查,得到结果基本都是仅仅能在主线程中更改 ui.子线程要 ...
- Android在子线程中更新UI(二)
MainActivity如下: package cc.testui2; import android.os.Bundle; import android.view.View; import andro ...
- Android在子线程中更新UI(一)
MainActivity如下: package cc.testui1; import android.os.Bundle; import android.os.Handler; import andr ...
- 如何在子线程中更新UI
一:报错情况 android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that creat ...
- Android开发UI之在子线程中更新UI
转自第一行代码-Android Android是不允许在子线程中进行UI操作的.在子线程中去执行耗时操作,然后根据任务的执行结果来更新相应的UI控件,需要用到Android提供的异步消息处理机制. 代 ...
- C#子线程中更新ui
本文实例总结了C#子线程更新UI控件的方法,对于桌面应用程序设计的UI界面控制来说非常有实用价值.分享给大家供大家参考之用.具体分析如下: 一般在winform C/S程序中经常会在子线程中更新控件的 ...
- Android子线程中更新UI的4种方法
方法一:用Handler 1.主线程中定义Handler: Handler mHandler = new Handler() { @Override public void handleMessage ...
随机推荐
- PHP 面试知识梳理
算法与数据结构 BTree和B+tree BTree B树是为了磁盘或者其他存储设备而设计的一种多叉平衡查找树,相对于二叉树,B树的每个内节点有多个分支,即多叉. 参考文章:https://www.j ...
- 《Java程序设计》第8周学习总结 20165218 2017-2018-1
20165218 2017-2018-1 <Java程序设计>第8周学习总结 教材学习内容总结 第12章 java多线程机制 java中的线程 计算机在任何给定时刻只能执行一个线程,多线程 ...
- git push要输入密码问题
git push突然每次都要输入密码了,这个问题困扰了两天,要无密码push,要保证两点. 1. git clone的url一定得是git开头的,不能是https开头的,这个容易被忽略,github ...
- 洛谷P1290 欧几里得的游戏
题目描述 欧几里德的两个后代Stan和Ollie正在玩一种数字游戏,这个游戏是他们的祖先欧几里德发明的.给定两个正整数M和N,从Stan开始,从其中较大的一个数,减去较小的数的正整数倍,当然,得到的数 ...
- stout代码分析之零
最近在使用mesos做高可用设计,在编译的过程中注意到mesos依赖stout,一个仅仅含有头文件的c++基础库.stout代码简洁,设计优雅,值得一读. stout从内容上可细分为以下几块: Pri ...
- 「Python」socket指南
开始 网络中的 Socket 和 Socket API 是用来跨网络的消息传送的,它提供了 进程间通信(IPC) 的一种形式.网络可以是逻辑的.本地的电脑网络,或者是可以物理连接到外网的网络,并且可以 ...
- 深入分析Java中的 == 和equals
关于Java中的 == 和equals的解释请看这位博主的文章 :http://www.cnblogs.com/dolphin0520/p/3592500.html 以下是我对这篇文章的一些扩展. 对 ...
- 关于C#微信公众号开发的前言说明
本人是昨天开始接触微信公众号开发的,昨天看一天官方文档,基本上晕乎乎的,刚开始接触这个真的有点困难,特别是C#在这方面的资料不多,不如php java方面的资料全. 所以我准备每天写一点关于C#微信开 ...
- Installing kubectl
Installing kubectl Kubernetes uses a command-line utility called kubectl for communicating with the ...
- vue使用插件 使用库
用插件1.引用import VueResource from 'vue-resource'2.使用Vue.use(VueResource); 用库(bootstrap alertify )1.引入: ...