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; } }