我将一些数据存入xml文件,大约有10万条。使用delphi的XMLDocument来操作。读取和写入都需要大约5分钟左右,非常慢。请问有没有什么方法可以极大提高速度?我不想用数据库保存这些数据如果实在不行的话,如果我用ini文件保存数据,能够显著提高读写速度吗?数据是标准的树型结构。没有google到可用的解决方案,求csdn高人现身

解决方案 »

  1.   

    用sax或者数据库的确可以提高速度
    但是
    1.我不想用数据。
    2.数据需要全部进入内存流,进行压缩加密等处理,用sax好像也不是办法,代码比较麻烦现在想改用ini文件保存读取,不知道速度是否会快很多
      

  2.   

    以前写了个函数解析的,不知丢哪了,找到了就给你贴出来。你将你的XML文件,给个简单示例出来,最好完整点。
      

  3.   

    xml文件结构类似这样的:
    <root>
      <root1>
       <node1>??</node1>
       <node2>?????</node2>
       <node3>
         <leaf1>1.23323</leaf1>
         <leaf2>1.23234323</leaf2>
         <leaf2>5.2334323</leaf3>
         <leaf4>4.5443</leaf4>
           ........上万条数据...   </node3>
      </root1>
      <root2>
       ..............
      </root2> 
    </root>
    xml最多到六层节点,在一个循环里读写数据,主要是读取leaf的数据太慢,在IBMT60,1.5G内存机器上,读取三万条数据大概要10秒。而数据量可能会超过30万条!!!要求不能使用数据库,代码量要少,因为需要存大量的复杂记录类型变量到文件。
    开始考虑过内存流的方法,但记录类型包含不定长string,包含二维的动态数组,在csdn上没有找到合适的方法写内存流。现在用xml可以实现存取,但速度实在无法忍受。再加上其它一些函数运算,控件动态生成,这个速度跟蜗牛似的。
      

  4.   

    现在以及尝试了写ini文件,速度一样的慢!
    procedure TForm1.Button1Click(Sender: TObject);
    var inifile:Tinifile;
         i:integer;
    begin
       inifile:=tinifile.Create('d:\1.ini');
       //gettime
       showmessage('ss');
       for i:=0 to 26000 do
       begin
       inifile.WriteInteger ('logdata','data'+inttostr(i),i);
       end;
       inifile.Destroy;
       showmessage('ee');
    end;
      

  5.   

    还真有人把xml当成数据库了啊
      

  6.   

    可以考虑一下用mybase包模式,速度还可以!
      

  7.   

    几十W条记录这样来应用,本来就是错误的~
    Access就OK了~也不用带什么库的
      

  8.   

    只找到老的版本,凑和用吧。
      PXMLNode = ^TXMLNode;
      TXMLNode = record
        Name: string;
        Value: string;
        Parent: PXMLNode;
        Attr: array of PXMLNode;
        Child: array of PXMLNode;
      end;function ParseXML(const XMLText: string; Root: PXMLNode): Boolean;  function GetElementName(var P: PChar; var IsEndElement: Boolean): string;
      var
        S: PChar;
      begin
        Result := '';
        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);
        SetString(Result, S, P - S);
        Result := Trim(Result);
        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): string;
      var
        S: PChar;
      begin
        Result := '';
        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);
        SetString(Result, S, P - S);
        Result := Trim(Result);
      end;  function GetContent(P: PChar): string;
      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);
        SetString(Result, S, P - S);
        Result := Trim(Result);
      end;  function GetXMLNode(Parent: PXMLNode; var XMLSrc: PChar; var XMLSize: Integer): Boolean;
      var              
        T, NodeName: string;
        L: Integer;
        Node: TXMLNode;
        Child: PXMLNode;
        IsEnd: Boolean;
      begin
        Result := False;
        FillChar(Node, SizeOf(Node), 0);
        NodeName := GetElementName(XMLSrc, IsEnd);
        if IsEnd then
        begin
          Result := GetXMLNode(Parent.Parent, XMLSrc, XMLSize);
          Exit;
        end;    if NodeName <> '' then
        begin
          Child := AllocMem(SizeOf(TXMLNode));
          SetLength(Child.Child, 0);
          Child^.Name := NodeName;
          Child^.Parent := Parent;
          if Assigned(Parent) then
          begin
            L := Length(Parent^.Child);
            SetLength(Parent^.Child, L + 1);
            Parent^.Child[L] := Child;
          end;
          T := GetNextElemntName(XMLSrc);
          if SameText(T, Child^.Name) then
          begin
            Child^.Value := GetContent(XMLSrc);
            OffsetElementEnd(XMLSrc);
            Result := GetXMLNode(Parent, XMLSrc, XMLSize);
          end else
            Result := GetXMLNode(Child, XMLSrc, XMLSize)
        end;
      end;var
      XMLSrc: PChar;
      XMLSize: Integer;
    begin
      XMLSrc := PChar(XMLText);
      XMLSize := Length(XMLText);
      Result := XMLSize > 0;
      if not Result then Exit;
      Result := GetXMLNode(Root, XMLSrc, XMLSize);
    end;
      

  9.   

    解析10W,关键是内存处理上,还是解析的方法,我上面函数会慢,是因为每节点用了New内存,而不是一次申请N个节点,而且用了递归,会造成堆栈溢出10W行的文本,一般都不超过10M,10M的文本load内存,一般不超过1s
      

  10.   

    分门别类
    分成多个XML文件
    多线程操作其实还是数据库
      

  11.   


    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;
      

  12.   

    我机子解析1W行的数据,不要20ms,所以我就不用多线程,数据库了。
      

  13.   

    我已经用内存流实现了,速度很快。
    在这里特别感谢errorc0de()现在还是不清楚为什么用XMLDocument解析的速度会那么慢。难道在内存访问树结构的数据非常耗时间吗?XMLDocument到底是如何在解析xml文件?
      

  14.   

    nativexml 可以试试,速度很快的
      

  15.   

    现在还是不清楚为什么用XMLDocument解析的速度会那么慢。难道在内存访问树结构的数据非常耗时间吗?XMLDocument到底是如何在解析xml文件?是通过字符匹配的。