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;

    运行起来。

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

  • 相关阅读:
    97. Interleaving String
    96. Unique Binary Search Trees
    95. Unique Binary Search Trees II
    94. Binary Tree Inorder Traversal
    odoo many2many字段 指定打开的form视图
    docker sentry 配置文件位置
    postgres 计算时差
    postgres 字符操作补位,字符切割
    postgres判断字符串是否为时间,数字
    odoo fields_view_get
  • 原文地址:https://www.cnblogs.com/xalion/p/10779308.html
Copyright © 2011-2022 走看看