码迷,mamicode.com
首页 > Web开发 > 详细

使用kbmmw 的REST 服务实现上传大文件

时间:2019-04-27 17:08:15      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:增加   比较   就会   ons   exists   pre   rms   assigned   客户   

我们在使用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 服务实现上传大文件

标签:增加   比较   就会   ons   exists   pre   rms   assigned   客户   

原文地址:https://www.cnblogs.com/xalion/p/10779308.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!