本文是參照博客園【CAP&船長(zhǎng)】的Demo衍生出來(lái)的。
主要是C#通過(guò)HttpWebRequest類通過(guò)Http協(xié)議并調(diào)用多線程下載Web資源。
思路: 1、獲取文件的總大小 2、設(shè)置啟動(dòng)的線程數(shù)目,并分配每個(gè)線程的下載的開始位置與下載的字節(jié)數(shù)大小 3、子線程下載成功后保存到臨時(shí)文件中 4、監(jiān)聽所有文件是否全部下載成功 5、如果所有子線程均下載完成則根據(jù)現(xiàn)在Id拼接起來(lái) 6、刪除臨時(shí)文件
簡(jiǎn)單封裝的類:
1、新建一個(gè)【CHttpDownload.cs】類 2、聲明必須的公共屬性與私有屬性以及變量
private int nThreadNum = 0; // 線程的個(gè)數(shù) private string strUrl = ""; // 下載地址 private string strSavePath = ""; // 文件保存地址 private System.Threading.Thread[] threads = null; // 線程數(shù)組 private int[] nStartPosition = null; // 每個(gè)線程的開始地址 private int[] nFileSize = null; //每個(gè)線程下載的大小 private bool[] bThreadState = null; // 線程下載狀態(tài) public bool bHasMerge { get; private set; } // 是否合并成功 public long lFileSizeAll { get; private set; } // 文件總大小 public int nBufferSize { get; set; } // 下載文件緩沖區(qū)大小 private int id = 0; // 標(biāo)記線程Id、臨時(shí)變量 2、構(gòu)造函數(shù) /// <summary> /// 構(gòu)造函數(shù) /// </summary> /// <param name="strUrl">文件下載地址Url</param> /// <param name="nThreadNum">所需要的線程數(shù)</param> public CHttpDownload(string strUrl, int nThreadNum) { /* 初始化下載地址、線程數(shù)、緩沖流大小 */ this.strUrl = strUrl; this.nThreadNum = nThreadNum; this.nBufferSize = 1024; Init(); } /// <summary> /// 初始化數(shù)據(jù)、設(shè)置每個(gè)線程的開始字節(jié)位置與字節(jié)大小 /// </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; // 前面線程下載的大小,最后一個(gè)線程下載全部 int nFileLastSize = nFileNormalSize + (int)lFileSizeAll % nThreadNum; // 最后一個(gè)線程下載的大小
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方法,功能為啟動(dòng)指定一個(gè)線程進(jìn)行下載,并保存到臨時(shí)文件中 /// <summary> /// 多線程開始接收 /// </summary> private void StartReceive() { id++; int nId = id - 1; string strFileName = "C:\\\\" + nId + ".tmp"; byte[] buffer = new byte[nBufferSize]; int nReadSize = 0; // 標(biāo)記本次讀到多少個(gè)數(shù)據(jù)
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]); // 設(shè)置流的開始位置與結(jié)束位置 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方法,功能為當(dāng)所有線程完成下載后進(jìn)行文件合并保存、并刪除臨時(shí)文件 /// <summary> /// 合并文件 /// </summary> private void MergeFiles() { while (true) // 驗(yàn)證所有線程是否全部接收完畢 { 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")) // 如果臨時(shí)文件存在則刪除 { File.Delete("C:\\\\" + i + ".tmp"); } } fs.Close(); }
5、新建StartDownload方法,為客戶調(diào)用多線程下載的方法 /// <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 |