delphi分块压缩使用http协议base64上传下载超大文件

delphi如何把json传递过来的base64值转成图片 阅读详情

delphi分块压缩使用http协议base64上传下载超大文件

目录

delphi分块压缩使用http协议base64上传下载超大文件

一、知识点:

二、需要注意的事项

2.1、优化上传下载的速度与并发性能的综合考虑

2.2、服务端http协议ContentType(mime-type)相关列表类型的注册

2.3、Buffer.size对Base64分块断点续传的影响

2.4、为何需使用TFileStream文件流替代内存流TMemoryStream

三、客户端代码

四、服务端代码


一、知识点:

1、Delphi自带的压缩解压单元system.zlib.pas中核心函数的使用

2、服务端http协议ContentType(mime-type)相关列表类型的注册

3、Base64编码的规则

4、为何要分块断点续传,并使用TFileStream文件流替代内存流TMemoryStream

5、Buffer.size对Base64分块断点续传的影响

6、优化上传下载的速度与并发性能的综合考虑

二、需要注意的事项

2.1、优化上传下载的速度与并发性能的综合考虑

2.2、服务端http协议ContentType(mime-type)相关列表类型的注册

2.3、Buffer.size对Base64分块断点续传的影响

         为何使用Base64?

        如果你仅仅是上传下载,而无需下载后H5加载,可以不必非得使用TBase64Encoding来编解码。

        否则,请使用Base64,它可以对html和URL进行编解码。可对相关代码进行客制化。

         Base64内容传输时需要注意的事项:

http分块上传或下载时,需注意,假如:每次拷贝接近1M:
            block := 6*(25*7)* 1024 * 1 =  8* 128 * 1024 * 1 ;//=1050KB
            提升服务器并发性能:拷贝分块大小,系统默认默认32kb
            一次上传,最多不能超过25M,似乎超过了,就没有响应
            Buffer不正确,分片时,会对Base64产生无规律的不可预期的影响,因为填充会出问题;块:6位字节的整数倍;
            系统默认buffer.size=32k,太小了:
            1.1、使用者会感觉太慢了
            1.2、某些服务器也可能做了限制:不允许连续发小包给它,它人为你是在http攻击
                   buffer.size=N个KB,太大了:
                   1.2.1、使用者内存不允许:上限 65535KB; 总之最好不要超过1M
                   1.2.2、服务器并发时,
                           内存(取决于服务器内存的大小)
                           磁盘(取决服务器硬盘通道即单位时间IO速度)、
                           网路带宽(取决你服务器的带宽)
                           它们受不了大的“冲击波"

​
        Base64 内容传输的W3C标准说明,请自行查阅互联网标准组织文档,rfc2045。

2.4、为何需使用TFileStream文件流替代内存流TMemoryStream

        并发时,压缩解压也好、上传下载也好,或使用内存流TMemoryStream,内存的开销太大、而且内存很昂贵,使用文件流TFileStream替代内存流,会有效避免此问题。

        用Delphi system.zlib.pas库单元函数压缩解压时,要特别注意:

        2.4.1、不要期待你能用常用的压缩解压工具,去打开system.zlib压缩文件,因为它是Delphi专用的压缩格式,加了密的;不过这样也很安全;

        2.4.2、无论压缩环节还是解压环节均不要TStream.CopyFrom

        因为这样,会丢失字节。而应当老实的用字节数组,逐个字节的读取或写入。

三、客户端代码

  ///<summary>RestFull上传文件函数(文件流方法):
    ///上传单个文件(TFileStream实例化抽象流:文件分段传参给服务器):
  ///</summary>
function CopyFileTFileStream(const Path: string;
    const BufSize :Integer= 6*(25*7)* 1024 * 1; //:BufSize大小默认值1050KB:为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;
begin
  if (Path.Trim='') 
    or (ServerPath.Trim='') 
    or (ServerFileName.Trim='') then
  begin
    AResultStr:='文件不能为空!';
    Result := AResultStr ;  
    exit;  
  end;
  if FileExists(Path) =true then
  begin
    AResultStr:='文件存在!';
    //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*  6*(25*7)* 1024 * 1); //:BufSize大小默认值1050KB:为1个分段) ); //:如果设置的较大:超内存需要控制,单独写例程
        //$F000;//$F000:61440:60kb//:System.Classes.fmCreate
        //:印象中好像最大缓冲区就这个大小,你自己核实吧,5兆我够了
      FileBufferCount:=0;  FileSize:=BufSize;
      AResultStr:=''; 
 
      for FileBufferCount := 1 to iCircle do
      begin  //文件流无需SetSize:
        //ATStream:将大文件流AWriteStream拆分成:
          //三位数的小临时文件.tmp的文件流:
        ACopyStream:= TMemoryStream.Create;
        ATStream:=TFileStream.Create( Path
          +FillBeforeString(IntToStr(FileBufferCount),10,'0')+'.tmp'
          ,fmCreate or fmOpenReadWrite);//:FillBeforeString:自写函数,字符串末尾向左补齐字符
          //:文件流,没有就产生、有就打开 //10位:足够1T的文件拆分
        try
          if FileSize < AWriteStream.Size then FileSize:= BufSize;
          if FileSize >= AWriteStream.Size then
            FileSize:=AWriteStream.Size - (iCircle-1) * BufSize;
          ReadCount := AWriteStream.Read( Buffer[0], FileSize );
 
          AResultStr:=AResultStr+','+IntToStr(FileSize); 
 
          if ReadCount > 0 then
            ATStream.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);//:需要的场景才这样做
          except
            AWriteStream.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 then
      begin 
        try 
          ifResult:=ServerMethods
           .mergeFilesUseTFileStream(ServerPath + ServerFileName);
          //while ifResult <>true do sleep(0);//:服务器方法成功执行需要时间,需要的场景才做
        except
          AWriteStream.disposeOf; ATStream.disposeOf; ACopyStream.disposeOf; 
          Result := '文件流合并错误'; exit;
        end;
        AResultStr:=  '文件上传成功';
        AWriteStream.disposeOf;
      end;
    end else
    begin
      //小文件:已知小于最小设定值,则直接复制数据:
      ACopyStream:= TMemoryStream.Create;
      ACopyStream.CopyFrom(AWriteStream,0);
      try  
        ifResult:=ServerMethods
         .upLoadFileFromTStreamBufferRead( ACopyStream,(ServerPath+ServerFileName) );
        //:服务器方法成功执行需要时间
        //while ifResult<>true do sleep(0);//:需要的场景才这样做
        AResultStr:=IntToStr(AWriteStream.Size);
      except
        AWriteStream.disposeOf; ACopyStream.disposeOf; 
        Result := '服务器出错了'; exit;
      end;
      if ifResult=true then
      begin
        AResultStr:= '文件上传成功';
        AWriteStream.disposeOf; 
      end;
    end;
 
  end else AResultStr:='文件不存在!';
 
  System.IOUtils.TDirectory.SetCurrentDirectory
    (System.IOUtils.TPath.GetLibraryPath);
 
  Result := AResultStr ;
end;
 

四、服务端代码

/// <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;
begin
  if FileExists(toFilePath)=true then
  begin
    TThread.Synchronize(nil,
    procedure
    begin
      TFile.Delete(toFilePath);
      MainServerForm.Memo_Errors.Lines.Add('删除文件:'+toFilePath.Trim);
    end
    );
  end;//:存在就先删除
  //删除后然后产生新文件:
  FS := TFileStream.Create(toFilePath, System.Classes.fmCreate); 
    //:常量默认fmCreate = $FF00; //: TFileStream create mode
  TThread.Synchronize(nil,
  procedure
  begin//测试:
    //MainServerForm.Memo_Errors.Lines.Add('新产生文件:'+toFilePath.Trim);
  end
  );
 
  try
    //if ATStream.Size = -1 then//:大小未知则一直读取到没有数据为止:
    begin
      SetLength( Buffer, BufSize );
      repeat
        ReadCount := ATStream.Read( Buffer[0], BufSize );
        if ReadCount > 0 then
          FS.WriteBuffer( Buffer[0], ReadCount );
        if ReadCount < BufSize then
          break;
      until ReadCount < BufSize;
    end //else FS.CopyFrom(ATStream, 0)
    ; //:大小已知则直接复制数据
  finally
    FS.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;
begin
  TDirectory.SetCurrentDirectory(System.IOUtils.TPath.GetLibraryPath);
  fileName:=System.IOUtils.TPath.GetLibraryPath + toFilePath;
  if TDirectory.Exists(TDirectory.GetParent(fileName)) then
  begin
    currPath:=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);//:搜索成功返回0
  if filesCount<>0 then
  begin
    System.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 do
  begin
    filesName.Add(SearchRec.Name);
    tmpTStream:=TFileStream.Create(SearchRec.Name,fmOpenRead);
    try
      //Vcl.Forms.Application.ProcessMessages;
        //:不卡界面:VCL将线程池TServerMethods1的消息事件交给应用的主线程
        //:不卡界面:FMX用线程同步方法TThread.Synchronize
      FileTStream.CopyFrom(tmpTStream,0);
      filesCount := FindNext(SearchRec);
    finally
      tmpTStream.disposeOf;  
    end;
  end;
  try
    for filesCount := 0 to filesName.Count-1 do
    begin
      if FileExists(filesName[filesCount].Trim)=true then
        TFile.Delete(filesName[filesCount].Trim);
    end;
  finally
    System.SysUtils.FindClose(SearchRec);//?不识别:需要带上前缀:System.SysUtils.
    filesName.disposeOf;  FileTStream.disposeOf; 
    TDirectory.SetCurrentDirectory(System.IOUtils.TPath.GetLibraryPath);
  end;
 
  Result :=true;
end;

cpu 8路全开,同时并发: 

喜欢的,就收藏并点个赞,鼓励我继续技术的原创写作及经验分享。

12、Delphi RTL实用功能全解析 本文深入解析了Delphi RTL中的多项实用功能,涵盖HTTP请求处理与TRACE命令安全验证、多种编码格式(如URL、HTML、Base64)的使用场景与代码示例,以及通过System.Zip实现文件压缩与解压的操作方法。同时介绍了基于TMessageManager的跨平台发布/订阅机制,用于实现代码解耦,提升应用可维护性。结合应用场景总结、流程图展示和代码优化建议,帮助开发者高效利用Delphi内置功能,提升开发效率与系统安全性。 阅读详情

相关推荐

Delphi7旧系统接入海康相机实现车牌识别:架构、代码与避坑

在工业现场,大量老上位机仍基于Delphi7开发,运行稳定却难以直接集成现代视觉能力。面对新增车牌识别需求,常见的海康网络相机SDK并未提供官方Delphi封装,直接将识别算法嵌入D7亦不现实。本文涉及的架构思路是:保留Delphi7主程序,通过封装HCNetSDK动态库完成登录、预览与抓图,再将图像转发给本地Python识别服务(如HyperLPR)处理。这种模式降低了老系统改造风险,也方便后续切换算法模型。在真实仓库门口场景中,利用窗口预览+独立抓图接口即可满足实时显示与车牌识别,同时需注意回调线程闪退

weixin_34246551的博客 446

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

Delphi处理高速文件上传下载的代码及思路 上传和下载是一对方向不同的概念,下面对应的客户端和服务器代码:掉个头,它就是下载;再掉个头,它就是上传。 一、思路 1、将大文件:分段(即常说的“断点”上传或下载)上传或下载 2、分别上传或下载这些分段 3、将上传或下载后的各“分段”文件流合并还原 4、关于加速(网上你经常看到“高速”上传或下载):若多线程分别上传或下载这些分段,即可提速。 你们去使用 高勇老师的代码,它是完全...

pulledup的博客 4682

DeepSeek-VL2 接入 Delphi 12.3:打造桌面多模态视觉推理控件

多模态推理正从云端 API 走向本地化部署,视觉语言模型(如 DeepSeek-VL2)能同时理解图像与文本,为合同信息抽取、工业缺陷检测等场景提供智能化支持。在 Delphi 桌面开发中集成此类能力,通常借助 vLLM 将模型封装为 OpenAI 兼容的 HTTP 服务,再通过 TNetHTTPClient 与 System.JSON 构建可复用的 VCL/FMX 控件,实现图片到结论的本地闭环。本文从部署模型服务、验证接口协议,到 Delphi 侧组装 data URI 与解析响应,再到封装异步控件和调

weixin_29047919的博客 319

Delphi 文件转换成Base64字符串

【代码】Delphi 文件转换成Base64字符串。

旭旭的博客 812

Delphi长连接实战:sgcWebSockets协议栈剖析与客户端服务端集成指南

WebSocket作为现代实时通信的核心协议,基于TCP提供全双工通信能力,通过RFC 6455定义的握手与帧格式实现低延迟双向数据交换。其协议栈涵盖握手响应计算、帧分片重组、掩码规则等关键细节,是构建长连接服务的基础。在工程实践中,WebSocket广泛用于行情推送、消息群发、远程控制等实时场景。Delphi开发者面对这类需求时,sgcWebSockets以完整源码交付,让开发者能深入协议驱动层调试,同时提供客户端心跳、断线重连、服务端广播、permessage-deflate压缩等生产级特性。本文从协议

weixin_33178839的博客 96

Delphi 12.3集成DeepSeek-VL2:多模态图像理解控件封装实战

多模态视觉语言模型能同时解析文本与图像,正成为AI应用落地的关键能力。OpenAI兼容的API接口大大降低了接入门槛,让传统桌面开发环境也能快速获得图像理解、图文对话等高级功能。Delphi作为老牌RAD工具,在维护遗留VCL项目时往往面临AI能力缺失的困境,而封装一个专用的视觉语言模型控件,恰好能在不重构现有架构的前提下补齐这一短板。集成过程涉及HTTP客户端选型、JSON结构化拼装、图像压缩与base64编码、流式响应解析以及线程安全的事件回调等核心技术点,每一步都隐藏着工程化细节。本文从DeepSee

weixin_33423874的博客 114

delphi压缩后使用http协议base64上传下载6G超大文件

delphi压缩后使用http协议base64上传下载6G超大文件 注:服务端软件,使用高勇出品GYRestServer系列。欢迎使用,加QQ群咨询:174483085 一、知识点: 1、Delphi自带的压缩解压单元system.zlib.pas中核心函数的使用 2、服务端http协议ContentType(mime-type)相关列表类型的注册 3、Base64编码的规则 4、为何要分块断点续传,并使用TFileStream文件流替代内存流TMemoryStream 5、Buffer.size

GuoGuoABC 587

Delphi 12.3集成DCPcrypt2:AES-256加密实战与避坑指南

对称加密是数据安全的基础,AES-256作为当前应用最广泛的块加密算法,常用于敏感信息的存储与传输保护。在Delphi 12.3中,DCPcrypt2以纯Object Pascal实现的控件库形态,让开发者无需依赖外部DLL即可获得AES、SHA-256、Blowfish等主流算法能力。它采用对象模型设计,通过TCipher基类派生出TDCP_rijndael等具体实现,使用时需关注密钥长度、IV与链模式的正确配置,CBC模式更是跨语言联调的关键。本文从源码安装、IDE路径配置到设计期包编译,完整梳理DCP

weixin_33946020的博客 417

Delphi Base64编码/解码及ZLib压缩/解压

最近做项目用到Base64编码及ZLib压缩,发现Delphi自带的Base64编码与java的Base64编码不一致,找了很多方法才解决这个问题,在这里来作一些总结: 压缩方法: StrToBase64(AnsiString(GZCompressStr(str))); 解压方法: GZDecompressStr(Base64ToStr(AnsiString(Str)));

小祝的专栏 1533

Delphi 11-13嵌入HTML渲染实战:控件安装、交互与避坑指南

HTML渲染组件为Delphi开发者提供了一种在原生VCL界面中嵌入现代网页技术的路径。其核心原理是通过独立渲染引擎(如基于WebView2的实现)替代老旧的IE内核,让HTML、CSS、JavaScript与Delphi事件模型深度互通,从而实现原生窗体与Web UI的混合开发。这一技术价值在于,复杂数据报表、KPI仪表盘等传统控件难以高效实现的场景,如今只需维护一套HTML模板,由Delphi端注入数据即可快速迭代。在ERP、MES、设备管理及PDA触屏等桌面应用中,尤其适用。本文针对Delphi 11

weixin_33981932的博客 368

Delphi7实现微信支付宝扫码支付完整源码项目

Delphi7是一款经典的快速应用开发(RAD)工具,以其高效的Object Pascal语言、丰富的VCL组件库和简洁的开发流程,广泛应用于企业级软件开发中。在扫码支付系统中,Delphi7凭借其强大的网络通信、数据处理和界面设计能力,成为实现支付接口集成与业务逻辑控制的理想选择。本章将介绍Delphi7的开发环境搭建、核心工具链使用,并探讨其在扫码支付系统中的技术优势与应用场景。

weixin_28487725的博客 803

Delphi图片转Base64编码小工具:简化网页图片嵌入的利器

Delphi图片转Base64编码小工具:简化网页图片嵌入的利器 【下载地址】Delphi图片转Base64编码小工具 这款Delphi小工具专为开发者设计,能够快速将jpg、png、bmp、gif等多种图片格式转换为base64编码。通过简单的拖放操作,用户即可轻松获取图片的base64编码,并直接复制到剪贴板,方便在...

gitblog_06734的博客 311

Delphi 12.3 JVCL控件库源码获取、编译与实战应用指南

在桌面应用开发中,第三方控件库是扩展开发环境功能、提升开发效率的关键工具。其原理在于通过封装成熟的代码模块,为开发者提供可复用的组件,从而避免重复造轮子。这类库的技术价值在于能显著加速复杂功能的实现,例如数据展示、用户界面交互和系统集成等。在Delphi生态中,面对企业级应用对高级UI组件和系统工具的需求,官方VCL有时难以满足,这时经过长期实践检验的第三方库就显得尤为重要。JVCL(JEDI Visual Component Library)作为一个开源、功能全面的Delphi控件库,涵盖了从增强型数据网

weixin_30729609的博客 360

mORMot使用基础

mORMot 名称来自Marmot,对,土拨鼠,俗称旱獭,是一种生活在高寒山区的动物。多数都在白天活动,喜群居,善掘土,所挖地道深达数米,内有铺草的居室,非常舒适。通常洞穴都会有两个以上的入口,以策安全。它们不贮存食物,而是在夏天往体内贮存脂肪以便冬季在洞内冬眠。mORMot = Manage Object Relational Mapping Over Territory目前Delphi生态系统...

weixin_33910434的博客 826

Delphi第三方控件集成实战:从TRichView源码编译到项目部署全解析

在软件开发中,第三方控件是扩展应用功能、提升开发效率的关键组件,其核心原理在于通过预编译的库或源码包,为开发者提供可复用的界面元素或功能模块。从技术价值看,优秀的控件能大幅减少重复开发工作,尤其在实现复杂UI、专业文档处理等场景中作用显著。然而,控件的集成与管理常面临版本兼容、环境配置等工程挑战,例如在Delphi生态中,处理像TRichView这类提供完整源码的专业富文本控件时,开发者常需解决“delphi 控件版本问题”导致的IDE加载异常,并应对“Full Source”带来的编译依赖与定制化复杂度。

weixin_30606461的博客 346

Delphi 在局域网内多播稳定传送大文件.rar

Delphi 在局域网内多播稳定传送大文件.rar

delphi接口带上请求头是什么意思_Gin框架中使用JWT进行接口验证

背景: 在如今前后端分离开发的大环境中,我们需要解决一些登陆,后期身份认证以及鉴权相关的事情,通常的方案就是采用请求头携带token的方式进行实现。本篇文章主要分享下在Golang语言下使用jwt-go来实现后端的token认证逻辑。JSON Web Token(JWT)是一个常用语HTTP的客户端和服务端间进行身份认证和鉴权的标准规范,使用JWT可以允许我们在用户和服务器之间传递安全可靠的信息...

weixin_39737233的博客 671

Delphi上传和下载文件

详细记录了整个Delphi上传和下载文件的整个过程,同时提供了源码,有兴趣的亲们可以试试

上一篇: Windows服务器或VM虚拟机下安装和部署VNC服务
下一篇: windows server 2012安装MS Sql Server 2000Ent企业版
专讲冷知识
博客等级 码龄15年 568粉丝 292原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专讲冷知识

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值