using Common.Model; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; 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() { this.isRun = false; dls.ForEach(dl => dl.Stop()); OnStopHandler(); } /// /// 开始下载 /// public void Start() { this.dlInfo.isReStart = false; WorkStart(); } /// /// 重新下载 /// public void ReStart() { this.dlInfo.isReStart = true; WorkStart(); } /// /// 下载 /// private void WorkStart() { new Action(() => { if (dlInfo.isReStart) { this.Stop(); } while (dls.Where(dl => !dl.isStopped).Count() > 0) { if (dlInfo.isReStart) Thread.Sleep(100); else return; } this.isRun = true; OnStartHandler(); //首次任务或者不支持断点续传的进入 if (dlInfo.isNewTask || (!dlInfo.isNewTask && !dlInfo.IsSupportMultiThreading)) { try { //第一次请求获取一小块数据,根据返回的情况判断是否支持断点续传 using (var rsp = HttpHelper.Download(dlInfo.downloadUrlList[0], 0, 0, dlInfo.method)) { //获取文件名,如果包含附件名称则取下附件,否则从url获取名称 var 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 头部,不为空说明支持断点续传 var 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 (this.dls.Where(td => !td.isFinish).Count() > 0 && this.isRun) { Thread.Sleep(100); } if ((this.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 (var fileStream = File.Open(realFilePath, FileMode.CreateNew)) { for (int i = 0; i < dlInfo.TaskInfoList.Count; i++) { var tempFile = dlInfo.TaskInfoList[i].filePath; using (var 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) { //创建正式文件名,如果已存在则加数字序号创建,避免覆盖 var fileIndex = 0; var 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) { this.dls = new List(); if (dlInfo.TaskInfoList != null) { foreach (var item in dlInfo.TaskInfoList) { var 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) { var pieceSize = (dlInfo.count) / dlInfo.taskCount; dlInfo.TaskInfoList = new List(); var rand = new Random(); var urlIndex = 0; for (int i = 0; i <= dlInfo.taskCount + 1; i++) { var from = (i * pieceSize); if (from >= dlInfo.count) break; var 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 (var writer = File.Open(filePath, FileMode.Append)) { using (stream) { var repeatTimes = 0; byte[] buffer = new byte[1024]; var length = 0; while ((length = stream.Read(buffer, 0, buffer.Length)) > 0 && this.isRun) { writer.Write(buffer, 0, length); this.fromIndex += length; if (repeatTimes % 5 == 0) { writer.Flush();//一定大小就刷一次缓冲区 OnDownloadHandler(); } repeatTimes++; } writer.Flush(); OnDownloadHandler(); } } } catch (Exception) { //异常也不影响 } } /// /// 开始下载 /// private void OnStartHandler() { new Action(() => { this.OnStart.Invoke(); }).BeginInvoke(null, null); } /// /// 暂停下载 /// private void OnStopHandler() { new Action(() => { this.OnStop.Invoke(); }).BeginInvoke(null, null); } /// /// 下载完成 /// private void OnFineshHandler() { new Action(() => { for (int i = 0; i < dlInfo.TaskInfoList.Count; i++) { var tempFile = dlInfo.TaskInfoList[i].filePath; File.Delete(tempFile); } this.OnFinsh.Invoke(dlInfo.saveFileName); }).BeginInvoke(null, null); } /// /// 下载进度 /// private void OnDownloadHandler() { new Action(() => { long current = GetDownloadLength(); this.OnDownload.Invoke(current, dlInfo.count, dlInfo.saveFileName); }).BeginInvoke(null, null); } /// /// 断开网络连接 /// private void OnDisconnectHandler() { new Action(() => { this.OnDisconnect.Invoke(dlInfo.saveFileName); }).BeginInvoke(null, null); } /// /// 当前下载进度 /// /// public long GetDownloadLength() { if (dlInfo.IsSupportMultiThreading) return dls.Sum(dl => dl.GetDownloadedCount()); else return this.fromIndex; } /// /// 获取保存文件名 /// /// public DownloadInfoModel GetFileInfo { get { return dlInfo; } } } }