代码语言
.
CSharp
.
JS
Java
Asp.Net
C
MSSQL
PHP
Css
PLSQL
Python
Shell
EBS
ASP
Perl
ObjC
VB.Net
VBS
MYSQL
GO
Delphi
AS
DB2
Domino
Rails
ActionScript
Scala
代码分类
文件
系统
字符串
数据库
网络相关
图形/GUI
多媒体
算法
游戏
Jquery
Extjs
Android
HTML5
菜单
网页交互
WinForm
控件
企业应用
安全与加密
脚本/批处理
开放平台
其它
【
Asp.NET
】
实现http多线程断点续传下载文件
作者:
艳双
/ 发布于
2019/11/4
/
1282
using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Net; using u8 = System.Byte; using u16 = System.UInt16; using s32 = System.Int32; using u32 = System.UInt32; using f32 = System.Single; namespace ConsoleApplication1 { public class HttpDownloadFile { public void SetURL(string URL) { mURL = URL; } //单线程下载文件大小阀值 public void SetSingleThFileSize(u32 FileSize) { mSingleThFileSize = FileSize; } //下载速度KB/S,需要外部循环调用Run函数更新这个值 public f32 GetDownloadSpeed() { return mDownloadSpeed / 1024; } //添加异步下载文件,这里提供输入文件大小的原因是 //方便灵活扩展,比如游戏更新,我们有可能先同步下载一个version.txt的 //文件里面包含类似md5和文件大小与本地比较找到需要下载的文件 //这时我们已经可以从version.txt里面提前知道需要下载文件的大小了 public void AddAsyncDownloadFile(string RemoteFilePath, string LocalFilePath, u32 RemoteFileSize = 0) { mDownloadFiles.Add(new DownloadFile(RemoteFilePath, LocalFilePath, RemoteFileSize)); } //同步下载文件 public bool SyncDownloadFile(string RemoteFilePath, string LocalFilePath) { try { var HttpRequest = WebRequest.Create(mURL + "//" + RemoteFilePath) as HttpWebRequest; var HttpResponse = HttpRequest.GetResponse() as HttpWebResponse; var HttpStream = HttpResponse.GetResponseStream(); _PrepareDirForFile(LocalFilePath); var OutStream = new FileStream(LocalFilePath, FileMode.Create); var Buffer = new Byte[1024]; var ReadBytes = 0; while (true) { ReadBytes = HttpStream.Read(Buffer, 0, Buffer.Length); if (ReadBytes <= 0) { break; } OutStream.Write(Buffer, 0, ReadBytes); } OutStream.Close(); HttpStream.Close(); HttpResponse.Close(); HttpRequest.Abort(); return true; } catch (WebException e) { Console.WriteLine(e.Message); return false; } catch (Exception e) { Console.WriteLine(e.Message); return false; } } public void StartAsyncDownloadFiles() { _CutFile(); Thread t; for (s32 i = 0; i < Environment.ProcessorCount; ++i) { t = new Thread(new ParameterizedThreadStart(_AsyncDownloadFiles)); t.Start(i); } //文件下载进度、总下载进度、下载完成事件请自行添加了... } void Run(f32 TimeDelta) { if (mDownloadBytes >= mTotalDownloadBytes) { return; } mTimeDelta += TimeDelta; if (mTimeDelta >= 1.0f) { mDownloadSpeed = mDownloadBytesCounter; mTimeDelta = .0f; mDownloadBytesCounter = 0; } } //获取文件大小,并且分割文件或者临时文件 void _CutFile() { HttpWebRequest HttpRequest; HttpWebResponse HttpResponse; DownloadFile MyFile; u32 Block = 0; u32 Mod = 0; FileStream InStream; string LocalTempFilePath = String.Empty; for (s32 i = 0; i < mDownloadFiles.Count; ++i) { MyFile = mDownloadFiles[i]; //得到文件大小 if (MyFile.mRemoteFileSize <= 0) { try { HttpRequest = WebRequest.Create(mURL + "//" + MyFile.mRemoteFilePath) as HttpWebRequest; HttpResponse = HttpRequest.GetResponse() as HttpWebResponse; MyFile.mRemoteFileSize = (u32)HttpResponse.ContentLength; HttpResponse.Close(); HttpRequest.Abort(); } catch (WebException e) { Console.WriteLine(e.Message); continue; } } //检测是否有未下载完毕的临时文件 for (s32 j = 0; j < Environment.ProcessorCount; ++j) { if (File.Exists(MyFile.mLocalFilePath + j.ToString())) { LocalTempFilePath = MyFile.mLocalFilePath + j.ToString(); break; } } //文件块大小 Block = MyFile.mRemoteFileSize / (u32)Environment.ProcessorCount; //余数 Mod = MyFile.mRemoteFileSize % (u32)Environment.ProcessorCount; if (LocalTempFilePath.Length > 0) { if (MyFile.mRemoteFileSize < mSingleThFileSize) { InStream = new FileStream(LocalTempFilePath, FileMode.Open); MyFile.mDownloadBytes += (u32)InStream.Length; MyFile.mFileBlocks.Enqueue(new DownloadFile.FileBlock((u32)InStream.Length, MyFile.mRemoteFileSize - 1, LocalTempFilePath)); InStream.Close(); } else { DownloadFile.FileBlock MyFileBlock; for (u32 j = 0; j < Environment.ProcessorCount; ++j) { LocalTempFilePath = MyFile.mLocalFilePath + j.ToString(); if (File.Exists(LocalTempFilePath)) { InStream = new FileStream(LocalTempFilePath, FileMode.Open); MyFile.mDownloadBytes += (u32)InStream.Length; MyFileBlock = new DownloadFile.FileBlock(j * Block + (u32)InStream.Length, (j + 1) * Block - 1, LocalTempFilePath); if (j == Environment.ProcessorCount - 1) { MyFileBlock.mEndBlock += Mod; } MyFile.mFileBlocks.Enqueue(MyFileBlock); InStream.Close(); } else { MyFileBlock = new DownloadFile.FileBlock(j * Block, (j + 1) * Block - 1, LocalTempFilePath); if (j == Environment.ProcessorCount - 1) { MyFileBlock.mEndBlock += Mod; } MyFile.mFileBlocks.Enqueue(MyFileBlock); } } } LocalTempFilePath = String.Empty; } else { if (MyFile.mRemoteFileSize < mSingleThFileSize) { MyFile.mFileBlocks.Enqueue(new DownloadFile.FileBlock(0, MyFile.mRemoteFileSize - 1)); } else { DownloadFile.FileBlock MyBlock; for (u32 j = 0; j < Environment.ProcessorCount; ++j) { MyBlock = new DownloadFile.FileBlock(j * Block, (j + 1) * Block - 1); if (j == Environment.ProcessorCount - 1) { MyBlock.mEndBlock += Mod; } MyFile.mFileBlocks.Enqueue(MyBlock); } } } mDownloadBytes += MyFile.mDownloadBytes; mTotalDownloadBytes += MyFile.mRemoteFileSize - MyFile.mDownloadBytes; } } private void _AsyncDownloadFiles(System.Object o) { var ThreadID = (u16)o; HttpWebRequest HttpRequest; HttpWebResponse HttpResponse; Stream HttpStream; FileStream OutStream; s32 ReadBytes = 0; Byte[] Buffer = new Byte[1024]; DownloadFile FileQueue; DownloadFile.FileBlock BlockQueue; while (true) { lock (this) { if (mDownloadFiles.Count <= 0) { break; } FileQueue = mDownloadFiles[0]; BlockQueue = FileQueue.mFileBlocks.Dequeue(); } try { //临时文件有可能恰好下完,这里就不用在请求了 if (BlockQueue.mBeginBlock > BlockQueue.mEndBlock) { goto SKIP_REQUEST; } HttpRequest = WebRequest.Create(mURL + "//" + FileQueue.mRemoteFilePath) as HttpWebRequest; HttpRequest.AddRange(BlockQueue.mBeginBlock, BlockQueue.mEndBlock); HttpResponse = HttpRequest.GetResponse() as HttpWebResponse; HttpStream = HttpResponse.GetResponseStream(); //下载全新的临时文件 if ("" == BlockQueue.mTempFilePath) { _PrepareDirForFile(FileQueue.mLocalFilePath + ThreadID.ToString()); OutStream = new FileStream(FileQueue.mLocalFilePath + ThreadID.ToString(), FileMode.Create); } //继续下载未下载完的临时文件 else { OutStream = new FileStream(BlockQueue.mTempFilePath, FileMode.Append); } while (true) { ReadBytes = HttpStream.Read(Buffer, 0, Buffer.Length); if (ReadBytes <= 0) { break; } OutStream.Write(Buffer, 0, ReadBytes); lock (this) { FileQueue.mDownloadBytes += (u32)ReadBytes; mDownloadBytesCounter = mDownloadBytes += (u32)ReadBytes; f32 FilePercent = (f32)FileQueue.mDownloadBytes / FileQueue.mRemoteFileSize;//事件调用文件进度 //onDownloadFilePercent(FilePercent * 100, FileQueue.mRemoteFilePath); f32 TotalPercent = (f32)mDownloadBytes / mTotalDownloadBytes;//事件调用总进度 //onDownloadPercent(TotalPercent * 100); } } OutStream.Close(); HttpStream.Close(); HttpResponse.Close(); HttpRequest.Abort(); SKIP_REQUEST: lock (this) { //一个文件所有块下载完毕,合并文件 if (FileQueue.mFileBlocks.Count <= 0) { _MergeFile(FileQueue, BlockQueue, ThreadID); mDownloadFiles.RemoveAt(0); } } } catch (WebException e) { Console.WriteLine(e.Message); } catch (Exception e) { Console.WriteLine(e.Message); } } } private void _MergeFile(DownloadFile MyFile, DownloadFile.FileBlock Block, u16 ThreadID) { if (MyFile.mRemoteFileSize < mSingleThFileSize) { if (File.Exists(MyFile.mLocalFilePath)) { File.Delete(MyFile.mLocalFilePath); } if ("" == Block.mTempFilePath) { File.Move(MyFile.mLocalFilePath + ThreadID.ToString(), MyFile.mLocalFilePath); } else { File.Move(Block.mTempFilePath, MyFile.mLocalFilePath); } return; } FileStream OutStream = new FileStream(MyFile.mLocalFilePath, FileMode.Create); FileStream InStream; s32 ReadBytes = 0; Byte[] Buffer = new Byte[1024]; for (u32 i = 0; i < Environment.ProcessorCount; ++i) { InStream = new FileStream(MyFile.mLocalFilePath + i.ToString(), FileMode.Open); while (true) { ReadBytes = InStream.Read(Buffer, 0, Buffer.Length); if (ReadBytes <= 0) { break; } OutStream.Write(Buffer, 0, ReadBytes); } InStream.Close(); File.Delete(MyFile.mLocalFilePath + i.ToString()); } OutStream.Close(); } private void _PrepareDirForFile(string FilePath) { var Dir = Path.GetDirectoryName(FilePath); if (false == Directory.Exists(Dir)) { Directory.CreateDirectory(Dir); } } class DownloadFile { public DownloadFile(string RemoteFilePath, string LocalFilePath, u32 RemoteFileSize = 0) { mRemoteFilePath = RemoteFilePath; mLocalFilePath = LocalFilePath; mRemoteFileSize = RemoteFileSize; mDownloadBytes = 0; } public string mRemoteFilePath; public string mLocalFilePath; public u32 mRemoteFileSize; public u32 mDownloadBytes; public class FileBlock { public FileBlock(u32 BeginBlock, u32 EndBlock, string TempFilePath = "") { mBeginBlock = BeginBlock; mEndBlock = EndBlock; mTempFilePath = TempFilePath; } public u32 mBeginBlock; public u32 mEndBlock; public string mTempFilePath; } public Queue<FileBlock> mFileBlocks = new Queue<FileBlock>(); } List<DownloadFile> mDownloadFiles = new List<DownloadFile>(); string mURL = "http://127.0.0.1:8080//download"; u32 mSingleThFileSize =1024 * 1024 * 10; f32 mDownloadSpeed = .0f; f32 mTimeDelta = .0f; u32 mDownloadBytesCounter = 0; u32 mDownloadBytes = 0; u32 mTotalDownloadBytes = 0; } class Program { static void Main(string[] args) { //代码写的不太完整,但是核心部分和流程已经可以作为参考(临时写的只是编译通过,未做测试) HttpDownloadFile Download = new HttpDownloadFile(); Download.SetURL( "http://127.0.0.1:8080//download" ); Download.SetSingleThFileSize( 1024 * 1024 * 10 ); Download.AddAsyncDownloadFile("1.rmvb", "download//1.rmvb"); Download.AddAsyncDownloadFile("2.rmvb", "download//2.rmvb"); Download.StartAsyncDownloadFiles(); Thread.Sleep(100000); } } }
试试其它关键字
同语言下
.
gzip压缩
.
实现http多线程断点续传下载文件
.
实现多线程断点续传下载大文件
.
生成字符串的 CheckSum
.
根据 UserAgent 获取浏览器的类型和版本
.
根据 Agent 判断是否是智能手机
.
隐藏手机号中间四位为*方法
.
合并图片(二维码和其他图片合并)
.
ASP.NET CORE中判断是否移动端打开网页
.
ASP.NET(C#)实现页面计时(定时)自动跳转
可能有用的
.
gzip压缩
.
实现http多线程断点续传下载文件
.
实现多线程断点续传下载大文件
.
生成字符串的 CheckSum
.
根据 UserAgent 获取浏览器的类型和版本
.
根据 Agent 判断是否是智能手机
.
隐藏手机号中间四位为*方法
.
合并图片(二维码和其他图片合并)
.
ASP.NET CORE中判断是否移动端打开网页
.
ASP.NET(C#)实现页面计时(定时)自动跳转
艳双
贡献的其它代码
(
11
)
.
监测 Nginx 访问日志 502 情况,并做相应动作
.
实现http多线程断点续传下载文件
.
过滤特殊字符,保留中文,字母,数字,和-
.
动态粘性页脚
.
WebApi通过HttpClient来调用Web Api接口
.
获取当前屏幕大小
.
棋子消除问题
.
筛法打印素数表
.
获取Excel Sheet名称,对特殊字符、重名进行了处理
.
点击退出按钮需要确认再退出
Copyright © 2004 - 2024 dezai.cn. All Rights Reserved
站长博客
粤ICP备13059550号-3