找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7223|回复: 0
收起左侧

C#多线程Http协议下载文件

[复制链接]
ID:83710 发表于 2015-6-25 16:36 | 显示全部楼层 |阅读模式
本文是参照博客园【CAP&船长】的Demo衍生出来的。

    主要是C#通过
HttpWebRequest类通过Http协议并调用多线程下载Web资源。

    思路:
    
    1、获取文件的总大小
    2、设置启动的线程数目,并分配每个线程的下载的开始位置与下载的字节数大小
    3、子线程下载成功后保存到临时文件中
    4、监听所有文件是否全部下载成功
    5、如果所有子线程均下载完成则根据现在Id拼接起来
    6、删除临时文件 

    简单封装的类: 

    1、新建一个【
CHttpDownload.cs】类
    2、声明必须的公共属性与私有属性以及变量

        private int nThreadNum = 0; // 线程的个数
        private string strUrl = ""; // 下载地址
        private string strSavePath = "";    // 文件保存地址
        private System.Threading.Thread[] threads = null; // 线程数组
        private int[] nStartPosition = null;    // 每个线程的开始地址
        private int[] nFileSize = null; //每个线程下载的大小
        private bool[] bThreadState = null; // 线程下载状态
        public bool bHasMerge { get; private set; }    // 是否合并成功
        public long lFileSizeAll { get; private set; }  // 文件总大小
        public int nBufferSize { get; set; }    // 下载文件缓冲区大小
        private int id = 0;      // 标记线程Id、临时变量

    2、构造函数 
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="strUrl">文件下载地址Url</param>
        /// <param name="nThreadNum">所需要的线程数</param>
        public CHttpDownload(string strUrl, int nThreadNum)
        {
            /* 初始化下载地址、线程数、缓冲流大小 */ 
            this.strUrl = strUrl;
            this.nThreadNum = nThreadNum;
            this.nBufferSize = 1024;
            Init();
        } 

        /// <summary>
        /// 初始化数据、设置每个线程的开始字节位置与字节大小
        /// </summary>
        private void Init()
        {
            threads = new System.Threading.Thread[this.nThreadNum];
            nStartPosition = new int[this.nThreadNum];
            nFileSize = new int[this.nThreadNum];
            bThreadState = new bool[this.nThreadNum];
            bHasMerge = false;

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.strUrl);
            lFileSizeAll = request.GetResponse().ContentLength; // 获取文件的总大小
            request.Abort();    // 端口本次连接

            int nFileNormalSize = (int)lFileSizeAll / nThreadNum;   // 前面线程下载的大小,最后一个线程下载全部
            int nFileLastSize = nFileNormalSize + (int)lFileSizeAll % nThreadNum;   // 最后一个线程下载的大小

            for (int i = 0; i < nThreadNum; i++)
            {
                bThreadState[i] = false;
                nStartPosition[i] = nFileNormalSize * i;
                if (i == nThreadNum - 1)
                {
                    nFileSize[i] = nFileLastSize - 1;
                }
                else
                {
                    nFileSize[i] = nFileNormalSize - 1;
                }
            }
        } 

    3、新建
StartReceive方法,功能为启动指定一个线程进行下载,并保存到临时文件中
        /// <summary>
        /// 多线程开始接收
        /// </summary>
        private void StartReceive()
        {
            id++;
            int nId = id - 1;
            string strFileName = "C:\\\\" + nId + ".tmp";
            byte[] buffer = new byte[nBufferSize];
            int nReadSize = 0;  // 标记本次读到多少个数据

            FileStream fs = new FileStream(strFileName, System.IO.FileMode.Create);
            Stream s = null;
            try
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.strUrl);
                request.AddRange(nStartPosition[nId], nStartPosition[nId] + nFileSize[nId]);    // 设置流的开始位置与结束位置
                s = request.GetResponse().GetResponseStream();
                nReadSize = s.Read(buffer, 0, nBufferSize);
                while (nReadSize > 0)
                {
                    fs.Write(buffer, 0, nReadSize);
                    nReadSize = s.Read(buffer, 0, nBufferSize);
                }
                fs.Close();
                s.Close();
            }
            catch (Exception ex)
            {
            }
            bThreadState[nId] = true;
        } 

    4、新建
MergeFiles方法,功能为当所有线程完成下载后进行文件合并保存、并删除临时文件
        
/// <summary>
        /// 合并文件 
        /// </summary>
        private void MergeFiles()
        {
            while (true)    // 验证所有线程是否全部接收完毕
            {
                bHasMerge = true;
                for (int i = 0; i < nThreadNum; i++)
                {
                    if (bThreadState[i] == false)
                    {
                        bHasMerge = false;
                        System.Threading.Thread.Sleep(100);
                        break;
                    }
                }
                if (bHasMerge == true)
                {
                    break;
                }
            }

            int nReadSize;
            byte[] bytes = new byte[nBufferSize];
            FileStream fs = new FileStream(strSavePath, FileMode.Create);
            FileStream fsTmp = null;
            for (int i = 0; i < nThreadNum; i++)
            {
                fsTmp = new FileStream("C:\\\\" + i + ".tmp", FileMode.Open);
                while (true)
                {
                    nReadSize = fsTmp.Read(bytes, 0, nBufferSize);
                    if (nReadSize > 0)
                    {
                        fs.Write(bytes, 0, nReadSize);
                    }
                    else
                    {
                        break;
                    }
                }
                fsTmp.Close();
                if (File.Exists("C:\\\\" + i + ".tmp")) // 如果临时文件存在则删除
                {
                    File.Delete("C:\\\\" + i + ".tmp");
                }
            }
            fs.Close();
        }  

    5、新建
StartDownload方法,为客户调用多线程下载的方法
        /// <summary>
        /// 开始下载文件
        /// </summary>
        /// <param name="strSaveFile">文件的保存地址</param>
        public void StartDownload(string strSaveFile)
        {
            this.strSavePath = strSaveFile;
            for (int i = 0; i < nThreadNum; i++)
            {
                threads[i] = new System.Threading.Thread(new System.Threading.ThreadStart(StartReceive));
                threads[i].Start();
            }
            System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(MergeFiles));
            t.Start();
        }  

    下载地址:http://www.msdn.top/documents/asp.net/
HttpDownload.zip
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表