我打开与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的大小,但获取数据真的很痛苦。
答案 0 :(得分:1)
Capture()
在循环中调用ReadLn()
,直到读取指定的终止符行(在您的示例中为空行)。
您需要知道每个XML文档的结束位置以及下一个XML文档的开始位置。如果每个文档之间没有明显的标记(空白行很好,只要每个XML文档以空白行之前的换行结束,并且XML中不包含任何空行),那么您只剩下选项是读取第一个文档的开始标记,继续阅读,直到找到相应的结束标记,然后读取下一个文档的开始标记并等待其结束标记,依此类推。
在这种情况下,您最好使用支持推送模型的XML解析器来处理它。您只需从套接字读取原始字节并按原样将它们推送到解析器中,并让它在遇到每个顶级文档元素的开头和结尾时告诉您。您可以缓冲解析器在这两个事件之间提供的任何数据,使用start事件清除/准备缓冲区和结束事件以完成/刷新缓冲区到数据库。
如果您不愿意/不能使用预先存在的XML库,则必须编写自己的解析器。
更新:您展示的示例Capture()
将其ADelim
参数设置为''
,这仅适用于XML文档由任意一个分隔的情况LF LF
或CR LF CR LF
序列。在这种情况下,您可以将该分隔符用作ATerminator
的{{1}}参数,并让它一次只读取1个完整文档,而不是完全使用ReadLn()
:
Capture()