2012-01-17 58 views
8

我写过一个DataSnap服务器方法,它返回一个TStream对象来传输文件。客户端应用程序调用该方法并正确读取流。我的问题是,在TStream对象可读取之前,方法调用需要一段时间才能完成,但在服务器端,我可以看到方法调用只需要一秒钟就可以创建要返回的对象。我希望流对象会立即返回,以便我可以读取流并显示下载进度的进度条。有另一种方法可以做到这一点吗?Delphi XE2 DataSnap - 通过TStream与进度条下载文件

服务器的方法很简单:

function TServerMethods.DespatchDocument(sCompanyID, sDocOurRef: string): TStream; 
var 
    sSourceFilePath: string; 
    strFileStream: TFileStream; 
begin 
    sSourceFilePath := GetDocumentPDFFilePath(sCompanyID, sDocOurRef); 

    strFileStream := TFileStream.Create(sSourceFilePath, fmOpenRead); 
    Result := strFileStream; 
end; 
+0

可能重复://计算器。 com/questions/6081841/progressbar-for-tresourcestream-delphi) – NGLN 2012-02-27 03:38:29

回答

2

这是我做到了,而回。我使用XE并没有机会清理它。

//服务器端:

function TServerMethods1.DownloadFile(out Size: Int64): TStream; 
begin 
    Result := TFileStream.Create('upload.fil', fmOpenRead or fmShareDenyNone); 
    Size := Result.Size; 

    Result.Position := 0; 
end; 

//客户端:

procedure TfMain.DownloadFile(Sender: TObject); 
var 
    RetStream: TStream; 
    Buffer: PByte; 
    Mem: TMemoryStream; 
    BytesRead: Integer; 
    DocumentId: Int64; 
    Size: Int64; 
    filename: WideString; 
    BufSize: Integer; 
begin 
    BufSize := 1024; 

    try 
     Mem := TMemoryStream.Create; 
     GetMem(Buffer, BufSize); 

     try 
     RetStream := FDownloadDS.DownloadFile(Size); 
     RetStream.Position := 0; 

     if (Size <> 0) then 
     begin 
      filename := 'download.fil'; 

      repeat 
      BytesRead := RetStream.Read(Pointer(Buffer)^, BufSize); 

      if (BytesRead > 0) then 
      begin 
       Mem.WriteBuffer(Pointer(Buffer)^, BytesRead); 
      end; 

      lStatus.Caption := IntToStr(Mem.Size) + '/' + IntToStr(Size); 
      Application.ProcessMessages; 

      until (BytesRead < BufSize); 

      if (Size <> Mem.Size) then 
      begin 
      raise Exception.Create('Error downloading file...'); 
      end; 
     end 
     else 
     begin 
      lStatus.Caption := ''; 
     end; 
     finally 
     FreeMem(Buffer, BufSize); 
     FreeAndNIl(Mem); 
     end; 
    except 
     on E: Exception do 
     begin 
     lErrorMessage.Caption := PChar(E.ClassName + ': ' + E.Message); 
     end; 
    end; 
end; 

,只要你喜欢你可以调整BUFSIZE。在这样做之前,我无法获得流的大小。我用XE2进行了实验,似乎没有相同的问题,但我正在上传。可能有更好的方法来检索流的大小。如果我很快得到答案,我会让你知道......

另一个说明 - 我还没有想出如何显示在服务器端的进度条。我仍然试图弄清楚这一点。

我希望这有助于!如果您有任何问题,请告诉我!

+0

不,我没有任何延迟。我一直在下载所有大小的文件(最多5 megs)。进度指示器工作得很好。我知道这听起来很奇怪,但有时我遇到了DataSnap在特定端口上行为的问题。我改变了不同的端口,一切正常。不幸的是,我从来没有机会弄清楚为什么或者我会告诉你。你的文件大小是多少?你试过BufSize的高低范围是多少? – Tadpole 2012-01-19 04:18:15

+0

我正在测试的文件不到5兆。我已经创建了与您一样的DataSnap方法,并且在客户端可以使用进度条读取流之前,方法调用需要大约40秒才能完成。我目前通过HTTP使用端口8080,使用TDSRESTConnection调用DataSnap方法。你如何连接到DataSnap服务? – 2012-01-19 09:44:21

+0

我还没有机会看看DataSnap的REST功能。我使用默认的211端口和客户端TSQLConnection通过TCP进行连接。我遇到了麻烦的应用程序,我设置了端口9999(和另一个应用程序到9998),问题消失了。我认为这是我的ISP的过滤机制。另一件事 - 我正在使用XE2 Update 3.你有这个吗?你用JSON做什么?我不得不用它修复一些东西,但是我无法想象它会影响你的下载。 如果你有一个小样本,我会建立它,看看我是否有同样的问题。 – Tadpole 2012-01-20 00:51:47

0

很高兴你有一些运气!这是我必须做的另一个解决方案。您可以参考此链接https://forums.embarcadero.com/thread.jspa?threadID=66490&tstart=0

跳水后在我的 “Data.DBXJSONReflect.pas” 找到的代码

程序TJSONPopulationCustomizer.PrePopulate(数据:TObject的; rttiContext:TRttiContext); ...

3473: rttiField.GetValue(Data).AsObject.Free; 
3474: rttiField.SetValue(Data, TValue.Empty); 

...

我想应该是这样的:的[进度为TResourceStream(德尔福)](HTTP

3473: rttiField.SetValue(Data, TValue.Empty); 
3474: rttiField.GetValue(Data).AsObject.Free;