DotNet 多线程下载

    public class MultiDownload
    {
        #region 初始化参数
 
        private int bufferSize = 512;//缓冲池大小
        private int threadNum;//线程数
 
        private string Url;//接受文件的URL
        //private List<string> Urls;
 
        private bool HasMerge;//文件合并标志
        private string DestFileName;
        private long receiveSize;//已经接收到的字节数
        private long fileSizeAll;//文件字节数
        private int RowIndex;//任务索引
 
        private List<ThreadInfo> threadinfos;
 
        private object lockPercent;//用于在加载下载进度是上锁
 
        private object lockFile;
 
        #endregion 初始化参数
 
        /// <summary>
        /// 下载进度
        /// </summary>
        /// <param name="rowIndex">任务索引</param>
        /// <param name="percent">进度</param>
        public delegate void DownloadingPercent(double percent);
 
        public event DownloadingPercent OnDownloadingPercent;
 
        /// <summary>
        /// 源文件大小
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="size"></param>
        public delegate void UpdateSrcFileSize(int rowIndex, long size);
 
        public event UpdateSrcFileSize OnUpdateSrcFileSize;
 
        /// <summary>
        /// 响应开始时间和结束时间的事件
        /// </summary>
        /// <param name="date"></param>
        public delegate void GetRunTime(DateTime date);
 
        public event GetRunTime OnGetStartTime;
 
        public event GetRunTime OnGetFinalTime;
 
        /// <summary>
        /// 响应改变控件状态事件,变为可使用
        /// </summary>
        public delegate void SetControlStaus();
 
        public event SetControlStaus OnSetControlStaus;
 
        public MultiDownload()
        {
            threadinfos = new List<ThreadInfo>();
            lockPercent = new object();
            lockFile = new object();
        }
 
        /// <summary>
        /// Http方式多线程下载一个文件
        /// </summary>
        /// <param name="srcFileUrl">文件地址</param>
        /// <param name="destFileName">保存全名</param>
        /// <param name="maxThreadNum">线程数</param>
        /// <param name="rowIndex">任务索引</param>
 
        public void DownloadFile(string srcFileUrl, string destFileName, int maxThreadNum = 5, int rowIndex = 0)
        {
            if (OnGetStartTime != null)
                OnGetStartTime(DateTime.Now);
            Url = srcFileUrl;
            DestFileName = destFileName;
            RowIndex = rowIndex;
            threadNum = maxThreadNum;//多少个线程下载
            receiveSize = 0;
 
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.Url);
            fileSizeAll = request.GetResponse().ContentLength;
            request.Abort();
            if (OnUpdateSrcFileSize != null)
                OnUpdateSrcFileSize(0, fileSizeAll);
 
            //初始化多线程
            List<Task> taskList = new List<Task>();
            //每个线程平均分配文件大小
            long pieceSize = (long)fileSizeAll / threadNum + (long)fileSizeAll % threadNum;
            for (int i = 0; i < threadNum; i++)
            {
                var resetEvent = new ManualResetEvent(false);
                ThreadInfo currentThread = new ThreadInfo();
                currentThread.ThreadId = i;
                currentThread.ThreadStatus = false;
                string filename = System.IO.Path.GetFileName(DestFileName);//带拓展名的文件名
                string dir = System.IO.Path.GetDirectoryName(DestFileName);     //返回文件所在目录
                currentThread.TmpFileName = string.Format($"{dir}{i}_{filename}.tmp");
                currentThread.Url = Url;
                currentThread.FileName = DestFileName;
 
                long startPosition = (i * pieceSize);
                currentThread.StartPosition = startPosition == 0 ? 0 : startPosition + 1;
                currentThread.FileSize = startPosition + pieceSize;
 
                threadinfos.Add(currentThread);
 
                taskList.Add(Task.Factory.StartNew(() =>
                {
                    ReceiveHttp(currentThread);
                }));
            }
 
            TaskFactory taskFactory = new TaskFactory();
            taskList.Add(taskFactory.ContinueWhenAll(taskList.ToArray(), tArray =>
            {
                //启动合并线程
                MergeFile();
                threadinfos.Clear();
                taskList.Clear();
            }));
        }
 
        /// <summary>
        /// Http方式接收一个区块
        /// </summary>
        private void ReceiveHttp(object thread)
        {
            FileStream fs = null;
            Stream ns = null;
            try
            {
                ThreadInfo currentThread = (ThreadInfo)thread;
                byte[] buffer = new byte[bufferSize];         // 接收缓冲区
                if (!File.Exists(currentThread.FileName))
                {
                    fs = new FileStream(currentThread.TmpFileName, FileMode.Create);
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(currentThread.Url);
                    request.Headers["Accept-Ranges"] = "bytes";
                    request.AddRange(currentThread.StartPosition, currentThread.FileSize);
                    ns = request.GetResponse().GetResponseStream();
                    int readSize = ns.Read(buffer, 0, bufferSize);
                    while (readSize > 0)
                    {
                        fs.Write(buffer, 0, readSize);
 
                        buffer = new byte[bufferSize];
 
                        readSize = ns.Read(buffer, 0, buffer.Length);
 
                        receiveSize += readSize;
                        double percent = (double)receiveSize / (double)fileSizeAll * 100;
                        //Debug.WriteLine($"下载进度:{percent}");
                        if (OnDownloadingPercent != null)
                            OnDownloadingPercent(percent);//触发下载进度事件
                    }
                }
                currentThread.ThreadStatus = true;
            }
            catch //这里不用处理异常,如果等待超时了,会自动继续等待到可以下载为止
            {
                //throw ex;
            }
            finally
            {
                fs?.Close();
                ns?.Close();
            }
        }
 
        /// <summary>
        /// 合并文件
        /// </summary>
        private void MergeFile()
        {
            int readSize;
            string downFileNamePath = DestFileName;
            byte[] buffer = new byte[bufferSize];
            int length = 0;
            using (FileStream fs = new FileStream(downFileNamePath, FileMode.Create))
            {
                foreach (var item in threadinfos.OrderBy(o => o.ThreadId))
                {
                    if (!File.Exists(item.TmpFileName)) continue;
                    var tempFile = item.TmpFileName;
                    Debug.WriteLine($"当前合并文件:{tempFile}");
                    using (FileStream tempStream = new FileStream(tempFile, FileMode.Open))
                    {
                        while ((length = tempStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            fs.Write(buffer, 0, length);
                        }
                        tempStream.Flush();
                    }
                    try
                    {
                        File.Delete(item.TmpFileName);
                    }
                    catch
                    {
                    }
                }
            }
 
            if (OnGetFinalTime != null)
                OnGetFinalTime(DateTime.Now);
            if (OnSetControlStaus != null)
                OnSetControlStaus();
        }
 
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            foreach (var item in threadinfos)
            {
                File.Delete(item.TmpFileName);
            }
        }
    }
 
    internal class ThreadInfo
    {
        public int ThreadId { get; set; }
        public bool ThreadStatus { get; set; }
        public long StartPosition { get; set; }
        public long FileSize { get; set; }
        public string Url { get; set; }
        public string TmpFileName { get; set; }
        public string FileName { get; set; }
        public int Times { get; set; }
    }

摘自:.net 多线程下载(已经测试通过)_分享你我 (javalc.com)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值