Delphi:Indy TIdTCPClient阅读XML

时间:2015-06-25 22:56:37

标签: xml delphi indy

我打开与TidTCPClient到服务器的套接字连接。 服务器开始向我发送不同XML数据的音调。 然而,ReadLn对我没有帮助,因为我不知道xml的起点和位置。停止。所以我决定使用Capture。这是正确的。但是当我从文档捕获中读取也调用ReadLn时,意味着它逐行读取。 30~40行XML需要1~2秒才能读取。所以我需要更快地阅读它。我可以使用ReadStream或任何其他有意义的东西吗?

我现在使用的代码:

procedure TfrmMain.ThreadRun(Sender: TIdThreadComponent);
var
  FData: TStringList;
  FMemory: TStringStream;
begin
  if Client.Connected = False then Exit;
  FData := TStringList.Create;
  Client.IOHandler.Capture(FData, '', False);
  FMemory := TStringStream.Create('',TEncoding.UTF8);
  FMemory.WriteString(FData.Text);
  CoInitialize(Nil);
  QInsert.ParamByName('XMLData').LoadFromStream(FMemory,ftBlob);
  QInsert.Execute;
  CoUninitialize;
  FMemory.Free;
  FData.Free;
end;

正如您所看到的那样,我将XML数据插入到本地表中,这很快就完成了,15ms~60ms取决于XML的大小,但获取数据真的很痛苦。

1 个答案:

答案 0 :(得分:1)

Capture()在循环中调用ReadLn(),直到读取指定的终止符行(在您的示例中为空行)。

您需要知道每个XML文档的结束位置以及下一个XML文档的开始位置。如果每个文档之间没有明显的标记(空白行很好,只要每个XML文档以空白行之前的换行结束,并且XML中不包含任何空行),那么您只剩下选项是读取第一个文档的开始标记,继续阅读,直到找到相应的结束标记,然后读取下一个文档的开始标记并等待其结束标记,依此类推。

在这种情况下,您最好使用支持推送模型的XML解析器来处理它。您只需从套接字读取原始字节并按原样将它们推送到解析器中,并让它在遇到每个顶级文档元素的开头和结尾时告诉您。您可以缓冲解析器在这两个事件之间提供的任何数据,使用start事件清除/准备缓冲区和结束事件以完成/刷新缓冲区到数据库。

如果您不愿意/不能使用预先存在的XML库,则必须编写自己的解析器。

更新:您展示的示例Capture()将其ADelim参数设置为'',这仅适用于XML文档由任意一个分隔的情况LF LFCR LF CR LF序列。在这种情况下,您可以将该分隔符用作ATerminator的{​​{1}}参数,并让它一次只读取1个完整文档,而不是完全使用ReadLn()

Capture()