使用kbmmw 的REST 服务实现上传大文件
Posted xalion
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用kbmmw 的REST 服务实现上传大文件相关的知识,希望对你有一定的参考价值。
我们在使用kbmmw的REST 服务时,经常会下载和上传大文件。例如100M以上的。kbmmw的rest服务中
提供标准的文件下载,上传功能,基本上就是打开文件,发送,接收,没有做特殊处理。这些对于文件比较小的
时候,问题不大,但是如果文件比较大,就会占用大量的服务器内存,导致服务器出现问题或者不响应。
为了解决这个问题,我们需要对文件上传、下载做特殊处理。以便节省服务器端的内存。
由于下载大文件有其他的一些方法,例如可以单独建立一个iis,apache,nginx等,或者可以利用httpsys 的静态文件
下载功能(以后有机会的话,我来讲一下)。
今天来实现以下大文件上传的方法,(当然,你也可以参照这个做一个大文件下载的功能)。主要思路是按照kbmmw 本身的
文件服务原理,把大文件切成小块,然后再上传。
首先在服务器端做一个上传文件服务。
[kbmMW_Rest(‘method:post, path:uploadfile,anonymousResult:False,freeResult:true‘)] [kbmMW_Method] function uploadfile( [kbmMW_Rest(‘value: "$filepath", required: true‘)] const filepath:string; [kbmMW_Rest(‘value: "$token", required: true‘)] const token:string; [kbmMW_Rest(‘value: "$position", required: true‘)] const position:string; [kbmMW_Rest(‘value: "$size", required: true‘)] const size:string; [kbmMW_Rest(‘value: "$final", required: true‘)] const final:string):string;
function TkbmMWCustomHTTPSmartService1.uploadfile(const filepath, token, position, size, final: string): string; const UPLOADPATH=‘d:\upload\‘; MaxFileSize=200*1024*1024; //上传文件大小不能超过200M errmsg=‘ERROR:‘; var fa:TkbmMWFileAccessPermissions; h:THandle; FileToken:integer; path:string; p:Pbyte; // l:integer; ref:TkbmMWFileReference; fofs,sz,newofs,maxsize:int64; bGC:boolean; FFinal:boolean; begin if not Assigned(FilePool) then begin result:=errmsg+‘No FilePool defined.‘; exit; end; if filepath=‘‘ then begin result:=errmsg+‘No filepath.‘; exit; end; if token=‘‘ then begin result:=errmsg+‘No token.‘; exit; end; if position=‘‘ then begin result:=errmsg+‘No position.‘; exit; end; fofs:=strtoint(position); if size=‘‘ then begin result:=errmsg+‘No size.‘; exit; end; sz:=strtoint(size); if sz>10*1024*1024 then begin result:=errmsg+‘blocksize too big.‘; exit; end; if ((final<>‘0‘) and (final<>‘1‘)) then begin result:=errmsg+‘final error.‘; exit; end; if final=‘0‘ then ffinal:=False else ffinal:=True; FileToken:=strtoint(token); path:= UPLOADPATH+filepath; // Determine file mode. if FileToken=-1 then begin // Check if file already exists and not overwrite permissions. if FileExists(path) and (not (mwfapOverwrite in fa)) then begin result:=errmsg+‘Permission denied‘; exit; end; end; // Append block to file. bGC:=false; ref:=FilePool.Access(path,mwfamOpenWrite,FileToken,h); try ref.DuringUpdate:=true; maxsize:=MaxFileSize; if FOfs>=0 then begin if (maxsize>0) and (FOfs+sz>maxSize) then begin result:=errmsg+‘File too big‘; exit; end; if FileSeek(h,FOfs,0)<0 then begin result:=errmsg+‘Cant position in file‘; exit; end; end else begin newofs:=FileSeek(h,0,2); if newofs<0 then begin result:=errmsg+‘Cant append to file‘; exit; end; if (maxsize>0) and (newofs+sz>maxSize) then begin result:=errmsg+‘File too big‘; exit; end; end; // Write requeststream to file. p:=RequestStream.Memory; if FileWrite(h,p^,sz)<>sz then begin ref.Invalidate; ref.DeleteOnGC:=true; bGC:=true; result:=errmsg+‘写文件失败.‘; exit; end; finally if FFinal then ref.DuringUpdate:=false; FilePool.ReleaseAccess(ref,h,FFinal); if bGC then FilePool.GarbageCollect; end; Result:=FileToken.ToString ; end;
编译运行即可。
客户端我们就直接增加一个上传过程。
procedure TForm1.Button3Click(Sender: TObject); const FBlockSize=2*1024*1024; baseurl=‘http://127.0.0.1/xalionrest‘; basepath=‘d:\‘; var HttpClient:TNetHTTPClient; requrl:string; filetoken:string; resp:IHTTPResponse; final:string; terminate:boolean; Stream:TFileStream; fm:integer; position,sz:string; pct:integer; RequestStream:Tmemorystream; LocalPath,filename:string; n,bs,ofs:integer; begin filename:= ‘delphi5.rar‘; localpath:=basepath+filename; fm:=fmOpenRead+fmShareDenyWrite; Stream:=TFileStream.Create(LocalPath,fm); HttpClient:= TNetHTTPClient.create(nil); RequestStream:= Tmemorystream.Create; filetoken:=‘-1‘; final:=‘0‘; try while true do begin if Stream.Size=0 then pct:=100 else pct:=trunc((Stream.Position / Stream.Size) * 100); position:=Stream.Position.ToString; sz:=Stream.Size.ToString; RequestStream.Clear; n:=FBlockSize; ofs:=Stream.Position; bs:=Stream.Size-ofs; if bs<=0 then break; if bs<=n then begin n:=bs; final:=‘1‘; end; RequestStream.CopyFrom(Stream,n); RequestStream.Position:=0; try requrl:= baseurl+‘/uploadfile?‘+‘filepath=‘+filename+‘&token=‘+filetoken+‘&position=‘+position+‘&size=‘+n.ToString+‘&final=‘+final; resp:=httpclient.Post(requrl,RequestStream);// filetoken:=resp.ContentAsString(); if pos(‘ERROR:‘,filetoken)>0 then begin showmessage(filetoken); exit; end; except showmessage(‘上传失败!‘); exit; end; if n<FBlockSize then break; end; showmessage(‘上传成功!‘); finally Stream.Free; HttpClient.Free; RequestStream.free; end; end;
运行起来。
我们看看服务器端的内存占用。
你可以看见服务的内存增长了,但是远远小于文件的大小。
以上是关于使用kbmmw 的REST 服务实现上传大文件的主要内容,如果未能解决你的问题,请参考以下文章