Delphi XE2 DataSnap - 使用进度条通过TStream下载文件

时间:2012-01-17 09:38:04

标签: delphi stream download progress datasnap

我编写了一个DataSnap服务器方法,该方法返回一个TStream对象来传输文件。客户端应用程序调用该方法并正确读取流。我的问题是在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;

2 个答案:

答案 0 :(得分: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并没有出现同样的问题,但我上传了。可能有更好的方法来检索流的大小。如果我很快得到答案,我会告诉你......

另一方面 - 我还没想出如何在服务器端显示进度条。我还在努力解决这个问题。

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

答案 1 :(得分:0)

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

潜入我在“Data.DBXJSONReflect.pas”

中找到的代码

procedure TJSONPopulationCustomizer.PrePopulate(Data:TObject; rttiContext:TRttiContext); ...

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

...

我认为应该是这样的:

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