Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Verbesserung für Code mit Stringlist


matze - So 23.10.05 21:58
Titel: Verbesserung für Code mit Stringlist
Hallo.
Ich brauchte für ein Projekt einen Code der aus Verschiedene INI Dateien die Werte aller Schlüssel herauszieht und in eine Variable eintägt.
Die Werte die in der INI datei unter einer bestimmten Section stehen, kenn ich nicht.
Daraus habe ich folgenden Code gemacht, der zwar funktioniert, aber nicht gut ist und noch langsamer ist als er gut ist.
Wie kann ich diesen denn schneller machen ?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
try
  values := TStringList.Create;
  temp := '';
  kunde.ReadSectionValues('con',values);
  for j := 0 to values.Count-1 do begin
    temp := temp + values.ValueFromIndex[j] + ' ' ;
  end;
  kunden[high(kunden)].searchstring := temp;
finally
  values.Free;
end;


retnyg - So 23.10.05 22:14

poste mal etwas mehr code, am besten ein lauffähiges beispiel mit demo-ini, dann kann dir geholfen werden


alzaimar - So 23.10.05 22:17

Schneller ginge das imho durch einen kleinen Dumb-Parser, ungefähr so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
  KundenIni := TStringList.Create;             // Einfach als Stringliste
  KundenIni.LoadFromFile('ThisCustomer.INI'); 
  i := 0;
  While KundenIni[i]<>'[con]' Do inc (i);       // goto section '[con]'
  Inc (i);
  repeat          // ab hier einlesen bis
    If i >= KundenIni.Count-1 then exit;        // dateiende oder bis 
    s := KundenIni[i];
    if Copy (s,1,1)='[' Then break;             // nächste INI-Section erreicht
    p := Pos('=',s)+1;                          // Value ist ja alles ab '='
    tmp := tmp + Copy (s,p,maxint)+' ';         // deinen tmp-String auffüllen
    inc (i);
  until false;

Das wäre streng iterativ, also ohne eventuell bremsende verschachtelte Schleifen, wie sie vielleicht beim IniFile auftreten könnten.


matze - So 23.10.05 22:27

das mit dem dumb-Parasre wer ich mal testen.

das ist ürbigens schon der code der so langsam ist.

der komplette code sieht so aus:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
try

  try
    progressbar1.Position := progressbar1.Position +1;
    aktion.Caption := 'erstelle Kundenindex...';
    application.ProcessMessages;
    kundenfiles := TStringList.Create;
    country := TStringList.Create;
    country.Sorted := true;
    country.Duplicates := dupIgnore;
    getfilesinDirectory (contactpath,'*.con',kundenfiles,false,true);
    progressbar2.Max := kundenfiles.Count;
    setlength (kunden,0);
    for i := 0 to kundenfiles.Count -1 do begin
      land := '';
      vname := '';
      nname := '';
      firma := '';
      progressbar2.Position := i+1;
      if i mod 200 = 0 then
        application.ProcessMessages;
      try
        kunde := TIniFile.Create(kundenfiles[i]);
        vname := kunde.ReadString('con','vname','');
        nname := kunde.ReadString('con','nname','');
        firma := kunde.ReadString('con','firma','');
        land := kunde.ReadString('con','land','');
        if not (land = ''then
          country.Add(land);
        if (firma = ''and (nname = ''then
          continue;
        setlength (kunden,length(kunden)+1);
        kunden[high(kunden)].id := stringreplace (extractfilename (kundenfiles[i]),'.con','',[rfReplaceAll]);
        if nname = '' then begin
          kunden[high(kunden)].dispname := firma;
          kunden[high(kunden)].startchar := (AnsiUppercase(firma))[1];
        end
        else begin
          kunden[high(kunden)].dispname := nname;
          kunden[high(kunden)].startchar := AnsiUppercase(nname)[1];
          if not (vname = ''then
            kunden[high(kunden)].dispname := kunden[high(kunden)].dispname + ', ' + vname;
        end;
        if not (kunden[high(kunden)].startchar in ['A'..'Z','Ä','Ö','Ü']) then
          kunden[high(kunden)].startchar := '1';
        if kunden[high(kunden)].startchar = 'Ä' then
          kunden[high(kunden)].startchar := 'A';
        if kunden[high(kunden)].startchar = 'Ö' then
          kunden[high(kunden)].startchar := 'O';
        if kunden[high(kunden)].startchar = 'Ü' then
          kunden[high(kunden)].startchar := 'U';
        kunden[high(kunden)].inactive := kunde.ReadBool('con','inactive',false);

        try
          values := TStringList.Create;
          temp := '';
          kunde.ReadSectionValues('con',values);
          for j := 0 to values.Count-1 do begin
            temp := temp + values.ValueFromIndex[j] + ' ' ;
          end;
          kunden[high(kunden)].searchstring := temp;
        finally
          values.Free;
        end;

      finally
        kunde.Free;
      end;
    end;
    country.SaveToFile(cachepath + 'country.dat'); 
  finally
    kundenfiles.Free;
    country.Free;
  end;


wie gesagt der code ist schon Asbach uralt. Aber ich hätte den gerne mal schneller und optimierter da ich ihn evtl wiederverwenden möchte


alzaimar - So 23.10.05 22:47

Statt TIniFile vielleicht TMemIniFile. Kann, muss bei Dir nicht schneller sein.
Aber eins ist klar: Das ReadString ist nicht schnell. Besser ist es, du erweiterst meinen 'Dumb-Parser' so, das er ab '[con]' die Angaben selbst einliest, du verzichtest dann komplett auf die TInifiles.

Zeile 32 könnte auch bremsen, denn wenn Du jedesmal das dynamische Array vergrößerst, geht ne ganze Menge Zeit flöten. Du weist doch, wie gross das Array 'kunden' wird. Mach nur 1x SetLength
und führe einen Zähler mit (eigentlich unnötig, da Zähler = Alte Length (kunden) + i)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
  KundenIni := TStringList.Create;             // Einfach als Stringliste
  KundenIni.LoadFromFile('ThisCustomer.INI'); 
  i := 0;
  While KundenIni[i]<>'[con]' Do inc (i);       // goto section '[con]'
  Inc (i);
  repeat          // ab hier einlesen bis
    If i >= KundenIni.Count-1 then exit;        // dateiende oder bis 
    s := KundenIni[i];
    if Copy (s,1,1)='[' Then break;             // nächste INI-Section erreicht
    p := Pos('=',s)+1;                          // Value ist ja alles ab '='
    v := Copy (s,p+1,MaxInt);
    tmp := tmp + v +' ';             // deinen tmp-String auffüllen
    If Length (s) > 0 then      // und gleich die Ausprägungen des Kunden
      case s[1of              // mit übernehmen, es reicht der 1. Buchstabe
        'v' : vName := v;            // um die Unterscheidung zu machen ;-)
        'n' : nName := v;
        'f' : Firma := v;
        'l' : Land := v;
      end;
    inc (i);
  until false;
// ... hier deine Weiterverarbeitung der Ausprägungen, speichern in das Array etc.


matze - Di 25.10.05 16:14

ich spiel mal ein bisschen damit rum. danke euch !