using Common.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
namespace Common.system
{
///
/// 下载方法
/// 创建人:赵耀
/// 创建时间:2018年10月30日
///
public class DownloadManager
{
private long fromIndex = 0;//开始下载的位置
private bool isRun = false;//是否正在进行
private DownloadInfoModel dlInfo;
private List dls = new List();
///
/// 开始下载
///
public event Action OnStart;
///
/// 停止下载
///
public event Action OnStop;
///
/// 下载进度
///
public event Action OnDownload;
///
/// 下载完成
///
public event Action OnFinsh;
///
/// 断开网络连接
///
public event Action OnDisconnect;
public DownloadManager(DownloadInfoModel dlInfo)
{
this.dlInfo = dlInfo;
}
///
/// 暂停
///
public void Stop()
{
isRun = false;
dls.ForEach(dl => dl.Stop());
OnStopHandler();
}
///
/// 开始下载
///
public void Start()
{
dlInfo.isReStart = false;
WorkStart();
}
///
/// 重新下载
///
public void ReStart()
{
dlInfo.isReStart = true;
WorkStart();
}
///
/// 下载
///
private void WorkStart()
{
new Action(() =>
{
if (dlInfo.isReStart)
{
Stop();
}
while (dls.Where(dl => !dl.isStopped).Count() > 0)
{
if (dlInfo.isReStart)
{
Thread.Sleep(100);
}
else
{
return;
}
}
isRun = true;
OnStartHandler();
//首次任务或者不支持断点续传的进入
if (dlInfo.isNewTask || (!dlInfo.isNewTask && !dlInfo.IsSupportMultiThreading))
{
try
{
//第一次请求获取一小块数据,根据返回的情况判断是否支持断点续传
using (System.Net.WebResponse rsp = HttpHelper.Download(dlInfo.downloadUrlList[0], 0, 0, dlInfo.method))
{
//获取文件名,如果包含附件名称则取下附件,否则从url获取名称
string Disposition = rsp.Headers["Content-Disposition"];
try
{
if (Disposition != null)
{
dlInfo.fileName = Disposition.Split('=')[1];
}
else
{
dlInfo.fileName = Path.GetFileName(rsp.ResponseUri.AbsolutePath);
}
}
catch (Exception)//无法获取文件名时 使用传入保存名称
{
dlInfo.fileName = dlInfo.saveFileName;
}
//默认给流总数
dlInfo.count = rsp.ContentLength;
//尝试获取 Content-Range 头部,不为空说明支持断点续传
string contentRange = rsp.Headers["Content-Range"];
if (contentRange != null)
{
//支持断点续传的话,就取range 这里的总数
dlInfo.count = long.Parse(rsp.Headers["Content-Range"].Split('/')[1]);
dlInfo.IsSupportMultiThreading = true;
//生成一个临时文件名
//var tempFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(dlInfo.fileName)).ToUpper();
//tempFileName = tempFileName.Length > 32 ? tempFileName.Substring(0, 32) : tempFileName;
//dlInfo.tempFileName = "test"; //tempFileName + DateTime.Now.ToString("yyyyMMddHHmmssfff");
///创建线程信息
///
GetTaskInfo(dlInfo);
}
else
{
//不支持断点续传则一开始就直接读完整流
Save(GetRealFileName(dlInfo), rsp.GetResponseStream());
OnFineshHandler();
}
}
}
catch (Exception ex)
{
string ErrMessage = "【下载】(DownloadManager):" + ex.Message;
LogHelper.WriteErrLog(ErrMessage, ex);
OnDisconnectHandler();
return;
}
dlInfo.isNewTask = false;
}
//如果支持断点续传采用这个
if (dlInfo.IsSupportMultiThreading)
{
StartTask(dlInfo);
//等待合并
while (dls.Where(td => !td.isFinish).Count() > 0 && isRun)
{
Thread.Sleep(100);
}
if ((dls.Where(td => !td.isFinish).Count() == 0))
{
CombineFiles(dlInfo);
OnFineshHandler();
}
}
}).BeginInvoke(null, null);
}
///
/// 合成文件
///
///
private void CombineFiles(DownloadInfoModel dlInfo)
{
string realFilePath = GetRealFileName(dlInfo);
//合并数据
byte[] buffer = new byte[2048];
int length = 0;
using (FileStream fileStream = File.Open(realFilePath, FileMode.CreateNew))
{
for (int i = 0; i < dlInfo.TaskInfoList.Count; i++)
{
string tempFile = dlInfo.TaskInfoList[i].filePath;
using (FileStream tempStream = File.Open(tempFile, FileMode.Open))
{
while ((length = tempStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, length);
}
tempStream.Flush();
}
//File.Delete(tempFile);
}
}
}
///
/// 创建文件
///
///
///
private static string GetRealFileName(DownloadInfoModel dlInfo)
{
//创建正式文件名,如果已存在则加数字序号创建,避免覆盖
int fileIndex = 0;
string realFilePath = Path.Combine(dlInfo.saveDir, dlInfo.saveFileName);
while (File.Exists(realFilePath))
{
realFilePath = Path.Combine(dlInfo.saveDir, string.Format("{0}_{1}", fileIndex++, dlInfo.fileName));
}
return realFilePath;
}
private void StartTask(DownloadInfoModel dlInfo)
{
dls = new List();
if (dlInfo.TaskInfoList != null)
{
foreach (TaskInfoModel item in dlInfo.TaskInfoList)
{
DownloadService dl = new DownloadService();
dl.OnDownload += OnDownloadHandler;
dl.OnDisconnect += OnDisconnectHandler;
dls.Add(dl);
try
{
dl.Start(item, dlInfo.isReStart);
}
catch (Exception ex)
{
string ErrMessage = "【下载】(DownloadManager):" + ex.Message;
LogHelper.WriteErrLog(ErrMessage, ex);
}
}
}
}
///
/// 创建下载任务
///
///
private void GetTaskInfo(DownloadInfoModel dlInfo)
{
long pieceSize = (dlInfo.count) / dlInfo.taskCount;
dlInfo.TaskInfoList = new List();
Random rand = new Random();
int urlIndex = 0;
for (int i = 0; i <= dlInfo.taskCount + 1; i++)
{
long from = (i * pieceSize);
if (from >= dlInfo.count)
{
break;
}
long to = from + pieceSize;
if (to >= dlInfo.count)
{
to = dlInfo.count;
}
dlInfo.TaskInfoList.Add(
new TaskInfoModel
{
method = dlInfo.method,
downloadUrl = dlInfo.downloadUrlList[urlIndex++],
filePath = Path.Combine(dlInfo.saveDir, dlInfo.tempFileName + ".temp" + i),
fromIndex = from,
toIndex = to
});
if (urlIndex >= dlInfo.downloadUrlList.Count)
{
urlIndex = 0;
}
}
}
///
/// 保存内容
///
///
///
private void Save(string filePath, Stream stream)
{
try
{
using (FileStream writer = File.Open(filePath, FileMode.Append))
{
using (stream)
{
int repeatTimes = 0;
byte[] buffer = new byte[1024];
int length = 0;
while ((length = stream.Read(buffer, 0, buffer.Length)) > 0 && isRun)
{
writer.Write(buffer, 0, length);
fromIndex += length;
if (repeatTimes % 5 == 0)
{
writer.Flush();//一定大小就刷一次缓冲区
OnDownloadHandler();
}
repeatTimes++;
}
writer.Flush();
OnDownloadHandler();
}
}
}
catch (Exception)
{
//异常也不影响
}
}
///
/// 开始下载
///
private void OnStartHandler()
{
new Action(() =>
{
OnStart.Invoke();
}).BeginInvoke(null, null);
}
///
/// 暂停下载
///
private void OnStopHandler()
{
new Action(() =>
{
OnStop.Invoke();
}).BeginInvoke(null, null);
}
///
/// 下载完成
///
private void OnFineshHandler()
{
new Action(() =>
{
for (int i = 0; i < dlInfo.TaskInfoList.Count; i++)
{
string tempFile = dlInfo.TaskInfoList[i].filePath;
File.Delete(tempFile);
}
OnFinsh.Invoke(dlInfo.saveFileName);
}).BeginInvoke(null, null);
}
///
/// 下载进度
///
private void OnDownloadHandler()
{
new Action(() =>
{
long current = GetDownloadLength();
OnDownload.Invoke(current, dlInfo.count, dlInfo.saveFileName);
}).BeginInvoke(null, null);
}
///
/// 断开网络连接
///
private void OnDisconnectHandler()
{
new Action(() =>
{
OnDisconnect.Invoke(dlInfo.saveFileName);
}).BeginInvoke(null, null);
}
///
/// 当前下载进度
///
///
public long GetDownloadLength()
{
if (dlInfo.IsSupportMultiThreading)
{
return dls.Sum(dl => dl.GetDownloadedCount());
}
else
{
return fromIndex;
}
}
///
/// 获取保存文件名
///
///
public DownloadInfoModel GetFileInfo => dlInfo;
}
}