如何使用Delphi XE6中的DataSnap传递和返回流?

3

如何在Delphi XE6中使用DataSnap传递和返回流?

当我调用服务器端方法时,我的流是正确的类,具有大小和位置。但是,当它传输到客户端时,该类不是我期望的,并且没有大小或位置。

//客户端代码

 procedure TForm1.brnGetReportClick(Sender: TObject);
    var
      RunReportObj: TRunReportObject;
      S: TStream;
      FS: TFileStream;
    begin
       ....
       try
          S:= (ClientModule1.ServerMethods1Client.getReport(RunReportObj));
          //ShowMessage('Class = ' + S.ClassName + #10#13 +
          //            'Size = ' + intToStr(S.Size) + #10#13 +
          //            'Position = ' + intToStr(S.Position));
          S.Position:= 0;
          FS:= TFileStream.Create('test.rpt', fmCreate or fmOpenWrite);
          FS.Position:= 0;
          try
            FS.CopyFrom(S, S.Size);
          finally
            FS.Free;
          end;
        finally
          S.Free
        end;
    end;

我在上面的代码中使用了调试showmessage,显示如下:

Class = TDBXStreamReaderStream
Size = -1
Position = 0

//服务器端方法

function getReport(const ARunReportObj: TRunReportObject): TStream;
var
  r: String;
  SS: TStringStream;
begin

   result:= TMemoryStream.Create;

   r := getRunReportJSON(ARunReportObj);
   SS := TStringStream.Create(r, TEncoding.ASCII);
   try
     try       
       ServerContainer1.idHttp1.Post
('https://imserver1.runit.com/isapi/isellitreporttest.dll/isellit', SS, result);
      ShowMessage('Class = ' + Result.ClassName + #10#13 +
                  'Size = ' + intToStr(result.Size) + #10#13 +
                  'Position = ' + intToStr(result.Position));
        Result.Position:= 0;
     except
     end;
   finally
    SS.Free;
   end;
end;

我在上述代码中调试时,显示如下:

Class = TMemoryStream 
Size = 373760 
Position = 373760
2个回答

4
这是设计上的规定。DataSnap只保证你从服务器获取到一个TStream,而不保证它实际上是哪个类。你可以从中读取,但仅限于此。 Position = 0也是预期的,因为这是你在服务器上设置的。另一方面,我不确定是否有其他任何东西作为Position = 0会有用,所以如果你在客户端侧得到Position = 0,我也不会感到惊讶。尽管如此,在服务器没有将其设置为0之前,流可能不会从预期位置开始。
对于Size属性,我参考了TStream文档:

Size属性通常表示流的大小(以字节为单位)。但是,TStream的后代可以使用-1来指示未知大小。当大小未知时,请使用TStream.Read的返回值来确定流的结尾。

你应该知道,DataSnap不一定会在调用getReport时传输流内容,但当你从客户端侧调用Read时可能会这样做。这允许像电影或广播播客之类的无尽流的存在。

1
谢谢您的回复。那么,为了修复我的代码(如果可能的话?),我只需要使用TStream.Read来获取大小,还是分块读取呢? - John
2
你的代码表明,你想将整个流存储到文件中。你不需要大小来做到这一点。如果你在CopyFrom的第二个参数中给出0,它将复制整个流。文档中是这样说的:"如果Count为0,CopyFrom在读取之前将源位置设置为0,然后将源的全部内容复制到流中。" - Uwe Raabe

0

服务器:

客户端到服务器

function Tform_methodos.SendStream(st:TStream): string;
var sm : TMemoryStream;
begin
    ...
    sm:=TMemoryStream.create;
    sm.LoadFromStream(st);
    sm.SaveToFile(pasta+'\test.bin');
    sm.free;
end;

服务器到客户端:

function Tform_methodos.GetStream(var size : integer):Tstream;
begin
    ...
    result:=TmemoryStream.create;
    TmemoryStream(result).LoadFromFile('test.bin');
    size:=TmemoryStream(result).Size;
end;

客户端: 客户端到服务器

var sm : TMemoryStream
    error : string;
begin
    ...
    sm:=TMemoryStream.create;
    sm.LoadFromFile('test.bin');
    error:=server.SendStream(sm);
    sm.Free;
end;

服务器到客户端
var sm : TmemoryStream;
    st : TStream;
    size : integer; 
begin
    ...
    sm:=TMemorystream.create;
    st:=server.GetStream(size);
    sm.CopyFrom(st,size);
    sm.SaveToFile('test.bin');
    sm.free;
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接