1. 程式人生 > >使用kbmmw 的REST 服務實現上傳大文件

使用kbmmw 的REST 服務實現上傳大文件

cti error pen load mode creat rto esp uri

我們在使用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 服務實現上傳大文件