zoukankan      html  css  js  c++  java
  • 使用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;

    运行起来。

    我们看看服务器端的内存占用。
    你可以看见服务的内存增长了,但是远远小于文件的大小。

  • 相关阅读:
    PHP 求多个数组的笛卡尔积,适用于求商品规格组合 【递归思想, 类似广度优先搜索】【原创】
    CCF推荐期刊会议
    SCI分区
    值和指针接收者的区别
    程序员练级攻略
    保险
    golang 有缓冲channel和无缓冲channel
    后台学习路线
    golang之反射
    atomic和mutex
  • 原文地址:https://www.cnblogs.com/xalion/p/10779308.html
Copyright © 2011-2022 走看看