delphi中使用XMLDocument读取大XML文件速度非常慢,求解决方案
我将一些数据存入xml文件,大约有10万条。使用delphi的XMLDocument来操作。读取和写入都需要大约5分钟左右,非常慢。
请问有没有什么方法可以极大提高速度?我不想用数据库保存这些数据
如果实在不行的话,如果我用ini文件保存数据,能够显著提高读写速度吗?
数据是标准的树型结构。
没有google到可用的解决方案,求csdn高人现身
[解决办法]
单是加载10几万行的文本,就会很耗时,
要是再解析,会更耗时
所以你应该从上面两方面入手
选一个简单一些的文件格式,来减少解析的复杂度
用内存映射提高文件读写速度
[解决办法]
const
MAXBUF_NODES = 10240;
type
TXMLStr = record
ptr: PChar;
len: Integer;
end;
PXMLNode = ^TXMLNode;
TXMLNode = record
Name: TXMLStr;
Value: TXMLStr;
Parent: PXMLNode;
Child: array of PXMLNode;
end;
PXMLDataArray = ^TXMLDataArray;
TXMLDataArray = record
Nodes: array [0..MAXBUF_NODES - 1] of TXMLNode;
next: PXMLDataArray;
end;
PXMLData = ^TXMLData;
TXMLData = record
Root: PXMLNode;
XMLData: TXMLStr;
BufCount: Integer;
IdleNodeBuffers: PXMLNode;
NodeBuffers: PXMLDataArray;
end;
procedure TrimStr(var V: TXMLStr);
var
P: PChar;
begin
while V.ptr^ = ' ' do
begin
Inc(V.ptr);
Dec(V.len);
end;
if V.len > 0 then
begin
P := V.ptr + V.Len - 1;
while P^ = ' ' do
begin
Dec(P);
Dec(V.len);
end;
end;
end;
function GetString(V: TXMLStr): string;
begin
if V.len > 0 then
begin
TrimStr(V);
SetString(Result, V.ptr, V.len);
end else
Result := ' ';
end;
function GetNewXMLNode(Data: PXMLData): PXMLNode;
var
nodes: PXMLDataArray;
begin
if Data.BufCount <= 0 then
begin
Nodes := AllocMem(SizeOf(TXMLDataArray));
Nodes.Next := Data.NodeBuffers;
Data.NodeBuffers := Nodes;
Data.IdleNodeBuffers := @Nodes.Nodes[0];
Data.BufCount := MAXBUF_NODES;
end;
Result := Data.IdleNodeBuffers;
FillChar(Result^, SizeOf(TXMLNode), 0);
Inc(Data.IdleNodeBuffers);
Dec(Data.BufCount);
end;
procedure InitXMLData(const AXMLDataString: string; var Data: TXMLData; CountOfNodeBuffers: Integer);
begin
Data.Root := nil;
Data.XMLData.len := Length(AXMLDataString);
Data.XMLData.ptr := AllocMem(Data.XMLData.len);
Move(AXMLDataString[1], Data.XMLData.ptr^, Data.XMLData.len);
Data.BufCount := 0;
Data.IdleNodeBuffers := nil;
Data.NodeBuffers := nil;
end;
procedure FreeXMLData(var Data: TXMLData);
var
Next, Nodes: PXMLDataArray;
begin
FreeMem(Data.XMLData.ptr);
Nodes := Data.NodeBuffers;
while Nodes <> nil do
begin
Next := Nodes.next;
FreeMem(Nodes);
Nodes := Next;
end;
FillChar(Data, SizeOf(Data), 0);
end;
procedure ParseXMLData(AData: PXMLData);
const
NULLXMLStr: TXMLStr = (ptr: nil; len: 0);
function GetElementName(var P: PChar; var IsEndElement: Boolean): TXMLStr;
var
S: PChar;
begin
Result := NULLXMLStr;
while not (P^ in [ ' < ', #0]) do Inc(P);
if P^ = ' < ' then Inc(P);
IsEndElement := P^ = '/ ';
{if IsEndElement then
begin
Inc(P);
while not (P^ in [ '> ', #0]) do Inc(P);
Inc(P);
Result := GetElementName(P, IsEndElement);
Exit;
end; }
if P^ = '/ ' then Inc(P);
if P^ = #0 then Exit;
S := P;
while not (P^ in [ '> ', #0]) do Inc(P);
Result.ptr := S;
Result.len := P - S;
if P^ = '> ' then Inc(P);
end;
procedure OffsetElementEnd(var P: PChar);
begin
while not (P^ in [ ' < ', #0]) do Inc(P);
if P^ = ' < ' then Inc(P);
if P^ = '/ ' then Inc(P);
if P^ = #0 then Exit;
while not (P^ in [ '> ', #0]) do Inc(P);
if P^ = '> ' then Inc(P);
end;
function GetNextElemntName(P: PChar): TXMLStr;
var
S: PChar;
begin
Result := NULLXMLStr;
while not (P^ in [ ' < ', #0]) do Inc(P);
if P^ = ' < ' then Inc(P);
if P^ = '/ ' then Inc(P);
if P^ = #0 then Exit;
S := P;
while not (P^ in [ '> ', #0]) do Inc(P);
Result.ptr := S;
Result.len := P - S;
end;
function GetContent(P: PChar): TXMLStr;
const
IgnoreChar = [#13, #10, #9, '& ', ' " ', #0];
var
S: PChar;
begin
while P^ in [ ' " ', #0] do Inc(P);
S := P;
while not (P^ in [ ' < ', #0]) do Inc(P);
while P^ in IgnoreChar do Dec(P);
Result.ptr := S;
Result.len := P - S;
end;
var
SrcPtr: PChar;
SrcLen: Integer;
procedure GetXMLNode(AParent: PXMLNode; var ASrc: PChar);
var
NextName, NodeName: TXMLStr;
L: Integer;
Node: TXMLNode;
Child: PXMLNode;
IsEnd: Boolean;
begin
while ASrc - SrcPtr < SrcLen do
begin
FillChar(Node, SizeOf(Node), 0);
NodeName := GetElementName(ASrc, IsEnd);
if IsEnd then
begin
GetXMLNode(AParent.Parent, ASrc);
break;
end;
if NodeName.len <= 0 then Continue;
Child := GetNewXMLNode(AData);
Child^.Name := NodeName;
Child^.Parent := AParent;
if Assigned(AParent) then
begin
L := Length(AParent^.Child);
SetLength(AParent^.Child, L + 1);
AParent^.Child[L] := Child;
end;
NextName := GetNextElemntName(ASrc);
// ==> SameText
if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
NextName.ptr, NextName.len,
NodeName.ptr, NodeName.len) - 2) = 0 then
begin
Child^.Value := GetContent(ASrc);
OffsetElementEnd(ASrc);
end else
GetXMLNode(Child, ASrc)
end;
end;
var
Src: PChar;
Len: Integer;
begin
Src := AData.XMLData.ptr;
Len := AData.XMLData.len;
SrcPtr := Src;
SrcLen := Len;
AData.Root := GetNewXMLNode(AData);
GetXMLNode(AData.Root, Src);
end;
procedure TForm1.Button1Click(Sender: TObject);
procedure DisplayNodes(Node: PXMLNode);
var
I, L: Integer;
begin
if not Assigned(Node) then Exit;
Memo1.Lines.Add(Format( '%s%s = %s ', [ ' ', GetString(Node.Name), GetString(Node.Value)]));
L := Length(Node.Child);
for I := 0 to L - 1 do
DisplayNodes(Node.Child[i]);
end;
var
XMLData: TXMLData;
List: TStringList;
Start: Cardinal;
begin
LIst := TStringList.Create;
List.LoadFromFile( '2.txt ');
Start := GetTickCount;
InitXMLData(List.Text, XMLData, 100);
ParseXMLData(@XMLData);
Caption := InttoStr(GetTickCount - Start);
DisplayNodes(XMLData.Root);
FreeXMLData(XMLData);
end;