lazarus中文官网,data1.cab文件下载
下载大文件时,可能需要断点重新开始下载。很难可靠地防止事故发生,尤其是当网络速度缓慢且不稳定时。如果您的下载意外中断,您就会遇到大麻烦。不得不从头下载它真是令人沮丧。断点续传可以有效解决意外中断的情况。如果要重新下载,不需要从头开始下载,只需从上次中断的地方继续下载即可,可以下载几GB到十几GB的文件。没问题。本文介绍如何使用Miniframe 开源Web 框架分别在Lazarus 和Delphi 中实现文件HTTP 下载断点续传功能。本文的demo还实现了批量下载文件以及将服务器上的文件同步到客户端的功能。断点续传原则:分块下载。下载后,客户端将它们一一合并并保存下载位置。如果下载意外中断,您可以从保存的位置开始下载。您还应确保中断后再次下载时,如果服务器上相应的文件已更新,则需要重新下载。否则,下载的文件将不正确。注意:以下代码可以在lazarus或delphi环境中使用。如需所有源代码和演示,请下载Miniframe 开源Web 框架: https://www.wyeditor.com/miniframe/或https://github.com/dajingshan/miniframe。
下载服务器端代码文件在服务器端恢复断点非常容易,只要客户端需要下载起始位置和指定的块大小。下面是服务器获取文件信息并下载文件的代码。
%@//脚本头、流程和函数定义程序代码;% %!//变量声明var i,lp: integer; FileName,relativePath, FromPath, ErrStr: string; json: TminiJson; FS: TFileStream; function GetOneDirFileInfo(Json: TminiJson; Path: string ): string;var Status: Integer; SearchRec: TSearchRec; json_sub: TminiJson;begin Path :=PathWithSlash(Path); SearchRec :=TSearchRec.Create; Status :=FindFirst(Path + '*.*', faAnyFile, SearchRec); 尝试Status=0 do beginif SearchRec.Attr and faDirectory=faDirectory then begin if (SearchRec.name '.') and (SearchRec.name '.') then GetOneDirFileInfo(Json, Path + SearchRec.Name + '\' ); end else begin FileName :=Path + SearchRec.Name; try if FileExists(FileName) then begin json_sub :=Pub.GetJson;json_sub.SO; //初始化或json.Init; json_sub.S['filename'] :=SearchRec. json.A['list'] :=json_sub; end; //print(ExceptionParam) end;//} end;Status :=FindNext(SearchRec); end; 最后FindClose(SearchRec); SearchRec.Free; end;//*) end;%%begin FromPath :='D:\code\delphi\sign\release file'; //下载源码目录json :=Pub.GetJson; //自己释放这样创建一个json对象。系统自动管理json .SO; //初始化或json.Init; //登录码为{if not Request.IsLogin('Logined') then begin json.S['retcode'] :=Check if '300'; json.S['retmsg'] :='您还没有登录(未登录)! '; print(json.AsJson(true)); exit; end;//} json.S['retcode'] :='200'; json.S['retmsg'] :='成功!'; if Request .V('opr')='1' then begin //获取服务上指定目录的文件信息GetOneDirFileInfo(Json, FromPath); end else if Request.V('opr')='2' then begin//下载指定文件中指定大小的块FromPath :=PathWithSlash(FromPath);relativePath :=Request.V('fn'); FileName :=FromPath +relativePath; Fs :=Pub.GetFS(FileName , fmShareDenyWrite, ErrStr ); if trim(ErrStr) '' then begin json.S['retcode'] :='300'; json.S['retmsg'] :=ErrStr; print(json.AsJson(true) ) ); exit ; end ; Fs.Position :=StrToInt(Request.V('pos')); Response.ContentStream :=TMemoryStream.Create; //无法使用Pub.GetMs,因为该对象是由Pub 创建的请注意。在动态脚本执行完毕之前,不会使用.GetMs。释放Response.ContentStream.CopyFrom(Fs, StrToInt(Request.V('size'))); //返回流数据。 Response.ContentType :='application/octet -stream'; end; print(json.AsJson( true));end;% 客户端代码客户端收到块后,将其合并。下载完所有块后,您需要将新下载的文件修改为与服务器上的文件相同。下面是客户端实现的主要代码。
procedure TMainForm.UpgradeBlock_Run(var ThreadRetInfo: TThreadRetInfo); const BlockSize=1024*1024; //1Mvar HTML, ToPath,relativePath, FN, Tmp, TmpFileName, FailFiles, SuccFiles, Newfn, TmpToPath: string; Json, TmpJson: T miniJson;lp, i , Number, HadUpSize, AllSize, AllBlockCount, MySize, MyNumber: Int64; Flag: boolean; SL, SLDate, SLSize, SLTmp: TStringlist; MS: TMemoryStream; //'获取文件列表。 '; ThreadRetInfo.Self.Synchronize(ThreadRetInfo.Self, MyUpdateface); //为什么不直接使用anonymous,因为laz不支持end;begin ToPath :='D:\superhtml'; //当前程序更新了If ExtractFilePath (ParamStr ( 0)) ThreadRetInfo.Ok :=false; HintMsg('正在获取文件列表.'); 否则HttpPost('/Interface/file client.html opr=1', '', ThreadRetInfo.ErrStr, ThreadRetInfo . HTML) then exit; if Pos('{', ThreadRetInfo.HTML) 1 then begin ThreadRetInfo.ErrStr :='请先检查脚本源代码配置是否正确。 '; End; End; ToPath :=Pub.PathWithSlash(ToPath); Json :=TminiJson.Create; SL :=TStringlist.Create; 尝试Json.LoadFromString(ThreadRetInfo.HTML); if json.S['retcode']='200' then begin TmpJson :=json.A['list']; for lp :=0 to TmpJson.length - 1 do begin HintMsg(lp.ToString + '/' + TmpJson.length.ToString + '检查文件:'+RelativePath);RelativePath :=TmpJson[lp].S['RelativePath'];如果trim(RelativePath)=''则继续;Flag :=FileExists(ToPath+RelativePath);如果Flag则开始if(PubFile. FileGetFileTimeA(ToPath +relativepath)=TmpJson[lp].S['FileTime']) 和(PubFile.FileGetFileSize(ToPath +relativePath)=TmpJson[lp].I['Size']) then else Flag :=false; end ; 如果不是Flag //这个文件必须更新begin SL.Add(RelativePath); SLDate.Add(TmpJson[lp].S ['FileTime']); SL Size.Add(TmpJson[lp] .S['Size']); end; end;//开始下载FailFiles :=''; SuccFiles :=''; HintMsg('必须更新总计' + IntToStr(SL.Count) + '文件存在.
'); 对于lp :=0 到SL.Count - 1 开始relativepath :=SL[lp]; 如果relativepath[1]='\' 则relativepath :=Copy(RelativePath, 2, MaxInt); FN :=ToPath +relativepath; //首先计算要分割的包数以处理进度Number :=0; HadUpSize :=0; AllSize :=StrToInt64(SLSize[lp]); AllBlockCount :=0; while true do begin AllBlockCount :=AllBlockCount + 1; if AllSize - HadUpSize=BlockSize then MySize :=BlockSize else MySize :=AllSize - HadUpSize; HadUpSize :=HadUpSize + MySize; if HadUpSize=AllSize then Break; end; //逐块开始下载,编号为:=0 ; HadUpSize :=0; //AllSize :=Fs.Size; //TmpToPath :=PubFile.FileGetTemporaryPath; Newfn :='@_' + PubPWD.GetMd5(SLDate[lp] + SLSize [lp]) + ExtractFileName(FN ); //Pub.GetClientUniqueCode; 如果FileExists(ToPath + Newfn) 和(FileExists(FN)) 则启动SLTmp.LoadFromFile(ToPath + Newfn); MyNumber :=StrToInt64( trim(SLTmp.Text)); Fs :=TFileStream .Create (FN, fmOpenWrite); end else begin MyNumber :=0; Fs :=TFileStream.Create(FN, fmCreate); end; try while true do begin HintMsg('正在下载文件[' + Pub.GetDeliBack(RelativePath, ' @ @ ') + '] [' + IntToStr(Number + 1) + '/' + IntToStr(AllBlockCount) + '] 包。
'); if AllSize - HadUpSize=BlockSize then MySize :=BlockSize else MySize :=AllSize - HadUpSize; Number :=Number + 1; if (MyNumber=0) 或(Number=MyNumber) 或(HadUpSize + MySize=AllSize) then beginfor I :=1 to 2 do //发生意外错误。如果没有,请重试HttpPost('/Interface/file client.html opr=2fn=' + UrlEncode(RelativePath) + 'pos=' + UrlEncode(IntToStr ( HadUpSize)) + 'size=' + UrlEncode (IntToStr(MySize) ), '', ThreadRetInfo.ErrStr, ThreadRetInfo.HTML, MS) then begin if I=2 then begin ThreadRetInfo.ErrStr :=Json.S['retmsg ' ]; exit; end else continue; end; if Pos('{ ', ThreadRetInfo.HTML) 1 then begin if I=2 then begin ThreadRetInfo.ErrStr :=Json.S['retmsg']; exit; end else continue ; end; Json.LoadFromString(ThreadRetInfo.HTML) ; if json.S ['retcode'] '200' then begin if I=2 then begin ThreadRetInfo.ErrStr :=Json.S['retmsg']; exit; end else continue ; end; Break;end; if MS=nil thenbegin ThreadRetInfo.ErrStr :='无法下载文件[' +relativepath + ']!' + json.S['retmsg']; exit;end elsebegin Fs.Position :=HadUpSize; MS.Position :=0; Fs.CopyFrom(MS, MS.Size); MS.Free; MS :=nil; SLTmp .Text :=Number.ToString; 尝试SLTmp.SaveToFile(ToPath + Newfn); 异常end;end; end; HadUpSize :=HadUpSize + MySize; if HadUpSize=AllSize 然后开始//所有下载完成Fs.Free;Fs :=nil;Sleep(10);PubFile.FileChangeFileDate(Fn, SLDate[lp]);DeleteFile(ToPath + Newfn);SuccFiles :=SuccFiles + #13#10 + RelativePath;break; end; end; 最后if Fs nil then Fs .Free; end; end; ThreadRetInfo.HTML :=''; ThreadRetInfo.HTML :='本次更新了以下文件:'#13#10 + SuccFiles; //if trim(FailFiles ) '' then //ThreadRetInfo.HTML :=trim(ThreadRetInfo.HTML + #13 #10'无法更新以下文件:'#13#10 + FailFiles); end; 最后SLTmp .Free; SLSize.Free ; SL.Free ; Json.Free; SLDate.Free; end; ThreadRetInfo.Ok :=true;end; 下面是演示运行界面。
天地劫幽城再临归真4-5攻略:第四章归真4-5八回合图文通关教学[多图],天地劫幽城再临归真4-5怎么样八回合内通
2024-04-03