Delphi处理高速文件上传下载的代码及思路

上传和下载是一对方向不同的概念,下面对应的客户端和服务器代码:掉个头,它就是下载;再掉个头,它就是上传。

一、思路

1、将大文件:分段(即常说的“断点”上传或下载)上传或下载

2、分别上传或下载这些分段

3、将上传或下载后的各“分段”文件流合并还原

4、关于加速(网上你经常看到“高速”上传或下载):若多线程分别上传或下载这些分段,即可提速。

你们去使用 高勇老师的代码,它是完全无问题;这里仅仅给大家提供一种提速的方案,高勇老师的代码,你按照这个思路稍作改装,即可高速上传或下载。

二、代码

2.1、客户端: 

  ///<summary>RestFull上传文件函数(文件流方法):///上传单个文件(TFileStream实例化抽象流:文件分段传参给服务器):///</summary>
function CopyFileTFileStream(const Path: string;const BufSize :Integer= (1*1024*1024); //:BufSize大小默认值1MB:为1个分段const ServerPath:string='api\upload\';const ServerFileName:string='A1.pdf' ):string;
var Buffer: TBytes; ReadCount,FileSize,FileBufferCount,iCircle: Integer;ATStream,AWriteStream: TFileStream; ACopyStream:TStream;AResultStr:string; ifResult: Boolean;
beginif (Path.Trim='') or (ServerPath.Trim='') or (ServerFileName.Trim='') thenbeginAResultStr:='文件不能为空!';Result := AResultStr ;  exit;  end;if FileExists(Path) =true thenbeginAResultStr:='文件存在!';//AWriteStream:读本地大文件的流:AWriteStream := TFileStream.Create( Path,fmOpenRead );iCircle:=ceil( AWriteStream.Size /BufSize );//:分几段读取,就写几个临时文件.tmp://大文件:已知大于最小设定值,则分段读取,直到读完为止:if AWriteStream.Size > BufSize then//:不能用FileSize显式的判断begin //:需要分数据包处理,如果是服务端是Datasnap默认32k的缓冲区(缓存,太JB小啦)://文件流无需SetSize,而是设置其Buffer:TBytes字节数组的长度://SetLength(Buffer, BufSize);SetLength( Buffer,(5*1024*1024) ); //:如果设置的较大:超内存需要控制,单独写例程//$F000;//$F000:61440:60kb//:System.Classes.fmCreate//:印象中好像最大缓冲区就这个大小,你自己核实吧,5兆我够了FileBufferCount:=0;  FileSize:=BufSize;AResultStr:=''; for FileBufferCount := 1 to iCircle dobegin  //文件流无需SetSize://ATStream:将大文件流AWriteStream拆分成://三位数的小临时文件.tmp的文件流:ACopyStream:= TMemoryStream.Create;ATStream:=TFileStream.Create( Path+FillBeforeString(IntToStr(FileBufferCount),10,'0')+'.tmp',fmCreate or fmOpenReadWrite);//:FillBeforeString:自写函数,字符串末尾向左补齐字符//:文件流,没有就产生、有就打开 //10位:足够1T的文件拆分tryif FileSize < AWriteStream.Size then FileSize:= BufSize;if FileSize >= AWriteStream.Size thenFileSize:=AWriteStream.Size - (iCircle-1) * BufSize;ReadCount := AWriteStream.Read( Buffer[0], FileSize );AResultStr:=AResultStr+','+IntToStr(FileSize); if ReadCount > 0 thenATStream.WriteBuffer(Buffer[0], ReadCount);ACopyStream.CopyFrom(ATStream,0);//:ACopyStream:由CopyFrom的调用者自己来释放try ifResult:=ServerMethods.upLoadFileFromTStreamBufferRead(ACopyStream,( ServerPath +ServerFileName+FillBeforeString(IntToStr(FileBufferCount),3,'0')+'.tmp') );//:服务器方法成功执行需要时间://while ifResult<>true do sleep(0);//:需要的场景才这样做exceptAWriteStream.disposeOf; ATStream.disposeOf; ACopyStream.disposeOf; Result := '流加载错误'; exit;end;  FileSize:=FileSize + BufSize;finally//传完该临时分段文件流释放它的句柄,并删除它对应的临时文件:ATStream.disposeOf; System.IOUtils.TFile.Delete(Path+FillBeforeString(IntToStr(FileBufferCount),3,'0')+'.tmp');end;end;//确保:全部临时分段文件流处理完成之后,发出合并文件请求,//将分段文件流还原为原始文件:if FileBufferCount =iCircle thenbegin try ifResult:=ServerMethods.mergeFilesUseTFileStream(ServerPath + ServerFileName);//while ifResult <>true do sleep(0);//:服务器方法成功执行需要时间,需要的场景才做exceptAWriteStream.disposeOf; ATStream.disposeOf; ACopyStream.disposeOf; Result := '文件流合并错误'; exit;end;AResultStr:=  '文件上传成功';AWriteStream.disposeOf;end;end elsebegin//小文件:已知小于最小设定值,则直接复制数据:ACopyStream:= TMemoryStream.Create;ACopyStream.CopyFrom(AWriteStream,0);try  ifResult:=ServerMethods.upLoadFileFromTStreamBufferRead( ACopyStream,(ServerPath+ServerFileName) );//:服务器方法成功执行需要时间//while ifResult<>true do sleep(0);//:需要的场景才这样做AResultStr:=IntToStr(AWriteStream.Size);exceptAWriteStream.disposeOf; ACopyStream.disposeOf; Result := '服务器出错了'; exit;end;if ifResult=true thenbeginAResultStr:= '文件上传成功';AWriteStream.disposeOf; end;end;end else AResultStr:='文件不存在!';System.IOUtils.TDirectory.SetCurrentDirectory(System.IOUtils.TPath.GetLibraryPath);Result := AResultStr ;
end;

2.2、服务端: 

/// <summary>将(大文件拆分后的)单个小临时文件上传到服务器的函数;///参数为文件数据流和服务器端应用库路径下的子路径 </summary>
function TServerMethods1.upLoadFileFromTStreamBufferRead(const ATStream:TStream; const toFilePath:string): Boolean;
const BufSize = $F000; //:默认$F000:61440:60kb的小文件 //System.Classes.fmCreate
var Buffer: TBytes; ReadCount,times: Integer; FS: TFileStream;
beginif FileExists(toFilePath)=true thenbeginTThread.Synchronize(nil,procedurebeginTFile.Delete(toFilePath);MainServerForm.Memo_Errors.Lines.Add('删除文件:'+toFilePath.Trim);end);end;//:存在就先删除//删除后然后产生新文件:FS := TFileStream.Create(toFilePath, System.Classes.fmCreate); //:常量默认fmCreate = $FF00; //: TFileStream create modeTThread.Synchronize(nil,procedurebegin//测试://MainServerForm.Memo_Errors.Lines.Add('新产生文件:'+toFilePath.Trim);end);try//if ATStream.Size = -1 then//:大小未知则一直读取到没有数据为止:beginSetLength( Buffer, BufSize );repeatReadCount := ATStream.Read( Buffer[0], BufSize );if ReadCount > 0 thenFS.WriteBuffer( Buffer[0], ReadCount );if ReadCount < BufSize thenbreak;until ReadCount < BufSize;end //else FS.CopyFrom(ATStream, 0); //:大小已知则直接复制数据finallyFS.Free;Result := True;end;
end;/// <summary>多文件流合并(用文件流方法实例化抽象流):</summary>
function TServerMethods1.mergeFilesUseTFileStream(const toFilePath:string): Boolean;
var filesCount :Integer;  SearchRec :TSearchRec;  currPath :string;fileName :string;  filesName :TStringList; FileTStream,tmpTStream :TStream;
beginTDirectory.SetCurrentDirectory(System.IOUtils.TPath.GetLibraryPath);fileName:=System.IOUtils.TPath.GetLibraryPath + toFilePath;if TDirectory.Exists(TDirectory.GetParent(fileName)) thenbegincurrPath:=TDirectory.GetParent(fileName);//强制路径产生://ForceDirectories(currPath) //DirectoryExists:路径是否存在//FileExists:文件是否存在:uses System.SysUtils;TDirectory.SetCurrentDirectory(currPath);//:进入该路径(设置当前路径并进入)if FileExists(fileName)=true then TFile.Delete(fileName);end;filesCount := FindFirst(currPath + '\' + '*.tmp', faAnyFile, SearchRec);//:搜索成功返回0if filesCount<>0 thenbeginSystem.SysUtils.FindClose(SearchRec);//?不识别:需要带上前缀:System.SysUtils.TDirectory.SetCurrentDirectory(System.IOUtils.TPath.GetLibraryPath);Result :=false; exit;end;     FileTStream:=TFileStream.Create(fileName,fmCreate);filesName:=TStringList.Create;while filesCount = 0 dobeginfilesName.Add(SearchRec.Name);tmpTStream:=TFileStream.Create(SearchRec.Name,fmOpenRead);try//Vcl.Forms.Application.ProcessMessages;//:不卡界面:VCL将线程池TServerMethods1的消息事件交给应用的主线程//:不卡界面:FMX用线程同步方法TThread.SynchronizeFileTStream.CopyFrom(tmpTStream,0);filesCount := FindNext(SearchRec);finallytmpTStream.disposeOf;  end;end;tryfor filesCount := 0 to filesName.Count-1 dobeginif FileExists(filesName[filesCount].Trim)=true thenTFile.Delete(filesName[filesCount].Trim);end;finallySystem.SysUtils.FindClose(SearchRec);//?不识别:需要带上前缀:System.SysUtils.filesName.disposeOf;  FileTStream.disposeOf; TDirectory.SetCurrentDirectory(System.IOUtils.TPath.GetLibraryPath);end;Result :=true;
end;

并行上传,CPU 8路全开,几乎全利用率满负荷上传。

本博客关联文章:源码下载:https://download.csdn.net/download/pulledup/12578989

《TTreeView完整的枚举和递归算法》 https://blog.csdn.net/pulledup/article/details/103687816

喜欢的话,就在下面点个赞、收藏就好了,方便看下次的分享:

Delphi处理高速文件上传下载的代码及思路相关推荐

  1. hibernate+servlet+mysql 实现easypoi_在Maven项目中使用easypoi完成Excel文件上传下载(示例代码)...

    导包: 1 2 3 cn.afterturn 4 easypoi-base 5 3.2.0 6 7 8 cn.afterturn 9 easypoi-web 10 3.2.0 11 12 13 cn. ...

  2. 2021-10-14 ContextType(MIME) 与 Java文件上传/下载

    ContextType(MIME) 与 Java文件上传/下载 ContextType(MIME) Text Image Audio Video Application Multipart 和 Mes ...

  3. SpringBoot文件上传下载以及优化过程 -- 个人笔记

    Java IO/NIO/AIO的知识体系图 博主最开始是用IO实现文件上传下载功能,但发现效率慢,于是使用了NIO 新的输入/输出 (NIO) 库是在 JDK 1.4 中引入的,弥补了原来的 I/O ...

  4. 直链文件上传下载网站分享(二)

    直链文件上传下载网站分享(一) 直链文件上传下载网站分享(二) 八.GM帮登陆器列表空间 九.墨涩网外链系统 十.树洞外链 十一.豆子外链 十二.凡人外链 十三.图钉外链 十四.小西外链 直链文件上传 ...

  5. 教你如何实现c#文件上传下载功能

    简单介绍一下c#文件上传下载功能实现. NuGet 安装SqlSugar Model文件下新建 DbContext 类 public class DbContext {public DbContext ...

  6. [C# 网络编程系列]专题十一:实现一个基于FTP协议的程序——文件上传下载器...

    引言: 在这个专题将为大家揭开下FTP这个协议的面纱,其实学习知识和生活中的例子都是很相通的,就拿这个专题来说,要了解FTP协议然后根据FTP协议实现一个文件下载器,就和和追MM是差不多的过程的,相信 ...

  7. SpringMVC整合fastdfs-client-java实现web文件上传下载

    为什么80%的码农都做不了架构师?>>>    版权声明:本文为博主原创文章,转载请标明出处(http://blog.csdn.net/wlwlwlwl015)Thanks. 目录( ...

  8. JavaWeb实现文件上传下载功能实例解析

    转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...

  9. 文件上传 java web_JavaWeb 文件上传下载

    1. 文件上传下载概述 1.1. 什么是文件上传下载 所谓文件上传下载就是将本地文件上传到服务器端,从服务器端下载文件到本地的过程.例如目前网站需要上传头像.上传下载图片或网盘等功能都是利用文件上传下 ...

最新文章

  1. UML设计,可以设计程序的用例图、类图、活动图等_SurfaceView
  2. 2.1 Mini-batch 梯度下降-深度学习第二课《改善深层神经网络》-Stanford吴恩达教授
  3. 世界种业并购史 国际农民丰收节贸易会起底农化巨头构架
  4. 笔记本html连接电视机,WinXP系统的笔记本如何连接电视?笔记本连接液晶电视方法...
  5. Oracle 11g 之自动收集统计信息
  6. 好用的数学公式(持续更新中)
  7. Python实现二叉搜索树的删除功能
  8. 如何在C#中实现图片缩放
  9. it资产管理系统php,开源IT资产管理软件(GIPI)
  10. php里 \r\n换行问题
  11. 卸载iis express后80端口仍然被占用的解决方法
  12. 学生HTML个人网页作业作品:基于web在线汽车网站的设计与实现 (宝马轿车介绍)
  13. UBI文件系统的制作与挂载案例
  14. 一文了解基金投资的方法
  15. 【Ubantu】root密码设置
  16. 2C领域最后一个资本宠儿,快看成“超新Z世代”娱乐平台
  17. 文章分类标签数据库设计
  18. 火山PC枚举文件和枚举目录
  19. 更加美化输入框的方法
  20. 建造者模式——KFC点餐系统

热门文章

  1. 电脑故障维修判断指导大全(联想内部文件)
  2. StringRedisTemplate报NullPointerException
  3. DeepMind新作 | 给我1张图,生成30秒视频!
  4. HDFS磁盘满了扩容
  5. python数据可视化入门(六):棉棒图,箱线图,误差棒图
  6. 中国·希腊国家馆落户上海自贸区
  7. Qt绑定UI界面和Qt类的四种方法
  8. 2023高频前端面试题(持续更新 含答案)
  9. IIS 7.5 以下版本 配置多域名同ip SSL 网站
  10. 慕课网模抖音小程序 springboot笔记