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; //开始下载的位置 private bool _isRun; //是否正在进行 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 = ZHttpUtil.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.Logerror.Error(errMessage, ex); OnDisconnectHandler(); return; } _dlInfo.isNewTask = false; } //如果支持断点续传采用这个 if (_dlInfo.IsSupportMultiThreading) { StartTask(_dlInfo); //等待合并 while (_dls.Count(td => !td.isFinish) > 0 && _isRun) { Thread.Sleep(100); } if ((_dls.Count(td => !td.isFinish) == 0)) { CombineFiles(_dlInfo); OnFineshHandler(); } } }).BeginInvoke(null, null); } /// /// 合成文件 /// /// private void CombineFiles(DownloadInfoModel dlInfo) { string realFilePath = GetRealFileName(dlInfo); //合并数据 byte[] buffer = new byte[2048]; int length; 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.Logerror.Error(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; 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(() => { if (OnStart != null) { 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; } }