// 功能:通知文件下载事件 void NotifyDownEvent(string url, bool bSuc, DownResFile resInfo) { // 这里只是输出一个日志,用户自行扩展事件吧 MemBlock pBlock = new MemBlock(); pBlock.resFile = resInfo; PushWrite(pBlock); // 通知写线程关闭对应的文件 if (bSuc) { Debug.Log("文件下载成功,url:" + url); } else { Debug.LogError("文件下载失败,url:" + url); } }
void WriteBlock(MemBlock pBlock) { // 这里可以使用一个特殊的标记,表示文件下载完成的 if (pBlock.data == null) { // 在这里添加事件处理 if (pBlock.resFile != null) { if (pBlock.resFile.file != null) { pBlock.resFile.file.Close(); pBlock.resFile.file = null; } pBlock.resFile = null; } return; } // 必要的话,在这里记录一下下载的状态, 这个用户自行扩展吧 DownResFile resFile = pBlock.resFile; if (resFile.file == null) { string szLocalPathName = GetLocalPathNameByUrl(pBlock.url); if (pBlock.nFileOfset == 0) { if (File.Exists(szLocalPathName)) { File.Delete(szLocalPathName); } } resFile.file = new FileStream(szLocalPathName, FileMode.OpenOrCreate, FileAccess.Write); if (resFile.file == null) { Debug.LogError(szLocalPathName + "文件打开失败!"); } } FileStream file = resFile.file; if (file != null) { file.Seek(pBlock.nFileOfset, SeekOrigin.Begin); file.Write(pBlock.data, 0, pBlock.nDownSize); file.Flush(); } }
void DownFile(CHttp http, string url, int nFileSize, int nLastDownSize) { // 如果文件比较小的话,可以不分片下载,真正下载整个文件 if (nFileSize == 0) { CHttpDown.GetDownFileSize(url, out nFileSize); } DownResFile resInfo = new DownResFile(); resInfo.url = url; resInfo.nFileSize = 0; if (0 == nFileSize) { // 无法获取文件大小信息,整个下载吧 bool bSuc = DownPart(http, url, 0, 0, nFileSize, resInfo); NotifyDownEvent(url, bSuc, resInfo); return; } int nPageSize = 1024 * 300; // 分片的大小,应小于你的最大限制下载速度, 这里默认选用300K,读者自己根据项目修改 int nFileOffset = nLastDownSize; // 从上一次下载的位置接着下载 int nDownSize = 0; for (; nFileOffset < nFileSize; nFileOffset += nPageSize) { // 先限速 LimitSpeed(); // 开始分片下载 nDownSize = nFileOffset + nPageSize < nFileSize ? nPageSize : (nFileSize - nFileOffset); if (!DownPart(http, url, nFileOffset, nDownSize, nFileSize, resInfo)) { NotifyDownEvent(url, false, resInfo); return; } } NotifyDownEvent(url, true, resInfo); }
bool DownPart(CHttp http, string url, int nFileOffset, int nDownSize, int nFileSize, DownResFile resFile) { // 调用Http下载的代码 nDownSize = http.PrepareDown(url, nFileOffset, nDownSize, nDownSize == 0); if (nDownSize <= 0) { Debug.LogError("文件下载失败,url:" + url + "(" + nFileOffset + "-" + nDownSize + ")"); return(false); } // 将下载的内容提交到写线程 byte[] szTempBuf = null; int nCurDownSize = 0; int nRecTotal = 0; int nRecLen = 0; int nOffset = 0; nCurDownSize = nDownSize > 4096 ? 4096 : nDownSize; MemBlock pBlock = AllockBlock(url, nFileOffset, nCurDownSize, nFileSize); // 从内存池中取一个4K的内存片 while (nDownSize > 0 && !m_bNeedStop) { // 必要的话,在这里添加限速功能或限制接收速度的功能,以免网速太快,导致一秒内分配太多内存 //LimitSpeed(); nRecLen = http.FastReceiveMax(ref szTempBuf, ref nOffset, 4096 - nRecTotal); if (nRecLen > 0) { OnReceive(nRecLen); // 统计下载的流量 Array.Copy(szTempBuf, nOffset, pBlock.data, nRecTotal, nRecLen); nRecTotal += nRecLen; // 如果当前块接收满了 if (nRecTotal >= nCurDownSize) { pBlock.resFile = resFile; PushWrite(pBlock);// 提交写文件 nRecTotal = 0; nDownSize -= nCurDownSize; nFileOffset += nCurDownSize; nCurDownSize = nDownSize > 4096 ? 4096 : nDownSize; // 必要的话,加上限额等待 if (nCurDownSize > 0) { WaitBlock(1024 * 1024); // 检测当前内存池分配的总量,超过就挂起 pBlock = AllockBlock(url, nFileOffset, nCurDownSize, nFileSize); // 从内存池中取一个4K的内存片 } } } else { return(false); // 文件读取失败,可能是网络出问题了 } } return(true); }