C#多线程下载

网友投稿 952 2022-11-10

C#多线程-

C#多线程-

///

/// 部分-器 /// public class PartialDownloader { #region Variables /// /// 这部分完成事件 /// public event EventHandler DownloadPartCompleted; /// /// 部分-进度改变事件 /// public event EventHandler DownloadPartProgressChanged; /// /// 部分-停止事件 /// public event EventHandler DownloadPartStopped; HttpWebRequest _req; HttpWebResponse _resp; Stream _tempStream; FileStream _file; private readonly AsyncOperation _aop = AsyncOperationManager.CreateOperation(null); private readonly Stopwatch _stp; readonly int[] _lastSpeeds; int _counter; bool _stop, _wait; #endregion #region PartialDownloader /// /// 部分块- /// /// /// /// /// /// /// public PartialDownloader(string url, string dir, string fileGuid, int from, int to, bool rangeAllowed) { _from = from; _to = to; _url = url; _rangeAllowed = rangeAllowed; _fileGuid = fileGuid; _directory = dir; _lastSpeeds = new int[10]; _stp = new Stopwatch(); } #endregion void DownloadProcedure() { _file = new FileStream(FullPath, FileMode.Create, FileAccess.ReadWrite); #region Request-Response _req = WebRequest.Create(_url) as HttpWebRequest; if (_req != null) { _req.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)"; _req.AllowAutoRedirect = true; _req.MaximumAutomaticRedirections = 5; _req.ServicePoint.ConnectionLimit += 1; _req.ServicePoint.Expect100Continue = true; _req.ProtocolVersion = HttpVersion.Version10; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.SystemDefault; ServicePointManager.Expect100Continue = true; if (_rangeAllowed) _req.AddRange(_from, _to); _resp = _req.GetResponse() as HttpWebResponse; #endregion #region Some Stuff if (_resp != null) { _contentLength = _resp.ContentLength; if (_contentLength <= 0 || (_rangeAllowed && _contentLength != _to - _from + 1)) throw new Exception("Invalid response content"); _tempStream = _resp.GetResponseStream(); int bytesRead; byte[] buffer = new byte[4096]; _stp.Start(); #endregion #region Procedure Loop while (_tempStream != null && (bytesRead = _tempStream.Read(buffer, 0, buffer.Length)) > 0) { while (_wait) { } if (_totalBytesRead + bytesRead > _contentLength) bytesRead = (int)(_contentLength - _totalBytesRead); _file.Write(buffer, 0, bytesRead); _totalBytesRead += bytesRead; _lastSpeeds[_counter] = (int)(_totalBytesRead / Math.Ceiling(_stp.Elapsed.TotalSeconds)); _counter = (_counter >= 9) ? 0 : _counter + 1; int tempProgress = (int)(_totalBytesRead * 100 / _contentLength); if (_progress != tempProgress) { _progress = tempProgress; _aop.Post(state => { DownloadPartProgressChanged?.Invoke(this, EventArgs.Empty); }, null); } if (_stop || (_rangeAllowed && _totalBytesRead == _contentLength)) { break; } } #endregion #region Close Resources _file.Close(); _resp.Close(); } _tempStream?.Close(); _req.Abort(); } _stp.Stop(); #endregion #region Fire Events if (!_stop && DownloadPartCompleted != null) _aop.Post(state => { _completed = true; DownloadPartCompleted(this, EventArgs.Empty); }, null); if (_stop && DownloadPartStopped != null) _aop.Post(state => DownloadPartStopped(this, EventArgs.Empty), null); #endregion } #region Public Methods /// /// 启动- /// public void Start() { _stop = false; Thread procThread = new Thread(DownloadProcedure); procThread.Start(); } /// /// -停止 /// public void Stop() { _stop = true; } /// /// 暂停等待- /// public void Wait() { _wait = true; } /// /// 稍后唤醒 /// public void ResumeAfterWait() { _wait = false; } #endregion #region Property Variables private readonly int _from; private int _to; private readonly string _url; private readonly bool _rangeAllowed; private long _contentLength; private int _totalBytesRead; private readonly string _fileGuid; private readonly string _directory; private int _progress; private bool _completed; #endregion #region Properties /// /// -已停止 /// public bool Stopped => _stop; /// /// -已完成 /// public bool Completed => _completed; /// /// -进度 /// public int Progress => _progress; /// /// -目录 /// public string Directory => _directory; /// /// 文件名 /// public string FileName => _fileGuid; /// /// 已读字节数 /// public long TotalBytesRead => _totalBytesRead; /// /// 内容长度 /// public long ContentLength => _contentLength; /// /// RangeAllowed /// public bool RangeAllowed => _rangeAllowed; /// /// url /// public string Url => _url; /// /// to /// public int To { get => _to; set { _to = value; _contentLength = _to - _from + 1; } } /// /// from /// public int From => _from; /// /// 当前位置 /// public int CurrentPosition => _from + _totalBytesRead - 1; /// /// 剩余字节数 /// public int RemainingBytes => (int)(_contentLength - _totalBytesRead); /// /// 完整路径 /// public string FullPath => Path.Combine(_directory, _fileGuid); /// /// -速度 /// public int SpeedInBytes { get { if (_completed) return 0; int totalSpeeds = _lastSpeeds.Sum(); return totalSpeeds / 10; } } #endregion }

///

/// 文件合并改变事件 /// /// /// public delegate void FileMergeProgressChangedEventHandler(object sender, int e); /// /// 多线程-器 /// public class MultiThreadDownloader { #region 属性 private string _url; private bool _rangeAllowed; #endregion #region 公共属性 /// /// RangeAllowed /// public bool RangeAllowed { get => _rangeAllowed; set => _rangeAllowed = value; } /// /// 临时文件夹 /// public string TempFileDirectory { get; set; } /// /// url地址 /// public string Url { get => _url; set => _url = value; } /// /// 第几部分 /// public int NumberOfParts { get; set; } /// /// 已接收字节数 /// public long TotalBytesReceived => PartialDownloaderList.Where(t => t != null).Sum(t => t.TotalBytesRead); /// /// 总进度 /// public float TotalProgress { get; private set; } /// /// 文件大小 /// public long Size { get; private set; } /// /// -速度 /// public float TotalSpeedInBytes => PartialDownloaderList.Sum(t => t.SpeedInBytes); /// /// -块 /// public List PartialDownloaderList { get; } /// /// 文件路径 /// public string FilePath { get; set; } #endregion #region 变量 /// /// 总-进度更新事件 /// public event EventHandler TotalProgressChanged; /// 文件合并事件 /// public event FileMergeProgressChangedEventHandler FileMergeProgressChanged; private readonly AsyncOperation _aop; #endregion #region -管理器 /// /// 多线程-管理器 /// /// /// /// /// public MultiThreadDownloader(string sourceUrl, string tempDir, string savePath, int numOfParts) { _url = sourceUrl; NumberOfParts = numOfParts; TempFileDirectory = tempDir; PartialDownloaderList = new List(); _aop = AsyncOperationManager.CreateOperation(null); FilePath = savePath; } /// /// 多线程-管理器 /// /// /// /// public MultiThreadDownloader(string sourceUrl, string savePath, int numOfParts) : this(sourceUrl, null, savePath, numOfParts) { TempFileDirectory = Environment.GetEnvironmentVariable("temp"); } /// /// 多线程-管理器 /// /// /// public MultiThreadDownloader(string sourceUrl, int numOfParts) : this(sourceUrl, null, numOfParts) { } #endregion #region 事件 private void temp_DownloadPartCompleted(object sender, EventArgs e) { WaitOrResumeAll(PartialDownloaderList, true); if (TotalBytesReceived == Size) { UpdateProgress(); MergeParts(); return; } OrderByRemaining(PartialDownloaderList); int rem = PartialDownloaderList[0].RemainingBytes; if (rem < 50 * 1024) { WaitOrResumeAll(PartialDownloaderList, false); return; } int from = PartialDownloaderList[0].CurrentPosition + rem / 2; int to = PartialDownloaderList[0].To; if (from > to) { WaitOrResumeAll(PartialDownloaderList, false); return; } PartialDownloaderList[0].To = from - 1; WaitOrResumeAll(PartialDownloaderList, false); PartialDownloader temp = new PartialDownloader(_url, TempFileDirectory, Guid.NewGuid().ToString(), from, to, true); temp.DownloadPartCompleted += temp_DownloadPartCompleted; temp.DownloadPartProgressChanged += temp_DownloadPartProgressChanged; PartialDownloaderList.Add(temp); temp.Start(); } void temp_DownloadPartProgressChanged(object sender, EventArgs e) { UpdateProgress(); } void UpdateProgress() { int pr = (int)(TotalBytesReceived * 1d / Size * 100); if (TotalProgress != pr) { TotalProgress = pr; if (TotalProgressChanged != null) { _aop.Post(state => TotalProgressChanged(this, EventArgs.Empty), null); } } } #endregion #region 方法 void CreateFirstPartitions() { Size = GetContentLength(_url, ref _rangeAllowed, ref _url); int maximumPart = (int)(Size / (25 * 1024)); maximumPart = maximumPart == 0 ? 1 : maximumPart; if (!_rangeAllowed) NumberOfParts = 1; else if (NumberOfParts > maximumPart) NumberOfParts = maximumPart; for (int i = 0; i < NumberOfParts; i++) { PartialDownloader temp = CreateNewPd(i, NumberOfParts, Size); temp.DownloadPartProgressChanged += temp_DownloadPartProgressChanged; temp.DownloadPartCompleted += temp_DownloadPartCompleted; PartialDownloaderList.Add(temp); temp.Start(); } } void MergeParts() { List mergeOrderedList = SortPDsByFrom(PartialDownloaderList); using (var fs = new FileStream(FilePath, FileMode.Create, FileAccess.ReadWrite)) { long totalBytesWritten = 0; int mergeProgress = 0; foreach (var item in mergeOrderedList) { using (FileStream pds = new FileStream(item.FullPath, FileMode.Open, FileAccess.Read)) { byte[] buffer = new byte[4096]; int read; while ((read = pds.Read(buffer, 0, buffer.Length)) > 0) { fs.Write(buffer, 0, read); totalBytesWritten += read; int temp = (int)(totalBytesWritten * 1d / Size * 100); if (temp != mergeProgress && FileMergeProgressChanged != null) { mergeProgress = temp; _aop.Post(state => FileMergeProgressChanged(this, temp), null); } } } File.Delete(item.FullPath); } } } PartialDownloader CreateNewPd(int order, int parts, long contentLength) { int division = (int)contentLength / parts; int remaining = (int)contentLength % parts; int start = division * order; int end = start + division - 1; end += (order == parts - 1) ? remaining : 0; return new PartialDownloader(_url, TempFileDirectory, Guid.NewGuid().ToString(), start, end, true); } /// /// 暂停或继续 /// /// /// public static void WaitOrResumeAll(List list, bool wait) { foreach (PartialDownloader item in list) { if (wait) item.Wait(); else item.ResumeAfterWait(); } } /// /// 冒泡排序 /// /// private static void BubbleSort(List list) { bool switched = true; while (switched) { switched = false; for (int i = 0; i < list.Count - 1; i++) { if (list[i].RemainingBytes < list[i + 1].RemainingBytes) { PartialDownloader temp = list[i]; list[i] = list[i + 1]; list[i + 1] = temp; switched = true; } } } } /// /// Sorts the downloader by From property to merge the parts /// /// /// public static List SortPDsByFrom(List list) { return list.OrderBy(x => x.From).ToList(); } /// /// 按剩余时间排序 /// /// public static void OrderByRemaining(List list) { BubbleSort(list); } /// /// 获取内容长度 /// /// /// /// /// public static long GetContentLength(string url, ref bool rangeAllowed, ref string redirectedUrl) { HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest; req.UserAgent = "Mozilla/4.0 (compatible; MSIE 11.0; Windows NT 6.2; .NET CLR 1.0.3705;)"; req.ServicePoint.ConnectionLimit = 4; long ctl; using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse) { redirectedUrl = resp.ResponseUri.OriginalString; ctl = resp.ContentLength; rangeAllowed = resp.Headers.AllKeys.Select((v, i) => new { HeaderName = v, HeaderValue = resp.Headers[i] }).Any(k => k.HeaderName.ToLower().Contains("range") && k.HeaderValue.ToLower().Contains("byte")); resp.Close(); } req.Abort(); return ctl; } #endregion #region 公共方法 /// /// 暂停- /// public void Pause() { foreach (var t in PartialDownloaderList) { if (!t.Completed) t.Stop(); } Thread.Sleep(200); } /// /// 开始- /// public void Start() { Task th = new Task(CreateFirstPartitions); th.Start(); } /// /// 唤醒- /// public void Resume() { int count = PartialDownloaderList.Count; for (int i = 0; i < count; i++) { if (PartialDownloaderList[i].Stopped) { int from = PartialDownloaderList[i].CurrentPosition + 1; int to = PartialDownloaderList[i].To; if (from > to) continue; PartialDownloader temp = new PartialDownloader(_url, TempFileDirectory, Guid.NewGuid().ToString(), from, to, _rangeAllowed); temp.DownloadPartProgressChanged += temp_DownloadPartProgressChanged; temp.DownloadPartCompleted += temp_DownloadPartCompleted; PartialDownloaderList.Add(temp); PartialDownloaderList[i].To = PartialDownloaderList[i].CurrentPosition; temp.Start(); } } } #endregion }

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:在th中显示图片
下一篇:索引存储
相关文章

 发表评论

暂时没有评论,来抢沙发吧~