TStrings ist *unglaublich* langsam
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo!
Ich habe ein Problem bei einem Programm an dem ich gerade arbeite. Sicher habt ihr schon einmal von GTA (Grand Theft Auto) gehört und wenn ihr dort Erfahrung habt wisst ihr vielleicht, dass es rund um diese Spieleserie eine große internationale Fangemeinde gibt, die sich im speziellen mit dem Modden des Spiels beschäftigt. Da mich neue Autos und ähnliches weniger interessieren, bin ich meistens bei den Scriptern unterwegs. Die GTA-Engine nutzt eine binär-kompilierte Datei (main.scm). Diese hat einen recht simplen Aufbau, welcher sich hier nachlesen lässt: Klick. Nun gibt es für das (noch) neuste GTA "San Andreas" im Grunde nur zwei Editoren zum dekompilieren/neu kompilieren dieser Datei, von denen einer nicht mehr gewartet wird und unter massiven Fehlern leidet und ein zweiter (aus Russland), welcher "nur" Freeware ist und dem (meiner Meinung nach) noch einige Features fehlen um perfekt zu sein. Jedenfalls habe ich mir überlegt meine Delphi Erfahrung (müssten nun 3 Jahre sein) zu nutzen um einen weiteren Open-Source Editor zu basteln. Bisher allerdings hatte ich noch keine größere Erfahrung mit binären Dateien, doch TFileStream machte im gepufferten Zustand kaum Probleme, ganz im Gegensatz zu meinem alten Freund TStrings der scheinbar mit meiner massiven Anzahl an Updates kaum klarkommt. Die Standard main.scm ist ca. 3mb groß, getestet habe ich alles an einer 1kb main.scm und alles lief prima, doch schon bei rund 70kb macht mir TString massive Probleme. Wenn ich alle Ausgabe-Befehle auskommentiere läuft es innerhalb von zwei Sekunden durch, genau wie es sollte, mit TStrings wird es mit steigender kb Zahl immer langsamer (ersichtlich wenn man sich die abgearbeiteten kb ausgeben lässt), so dauert es von 2 auf 3 kb einige Sekunden und von 61 auf 62 ewige Jahre. Deshalb, nach dieser ewigen Einleitung, meine Frage was ich dagegen tun könnte. Hier der Quellcode der entsprechenden Funktion (muss evt. noch an einigen Stellen geändert werden ;)).
Delphi-Quellcode:
Angehängt mal das komplette Projekt, falls jemand eine Idee hat (beide scms [70kb + mini 1kb] sind mal mit drin, zum testen [Beide übrigens inoffiziell und somit nicht vom Copyright des Spieleherstellers betroffen]). Oh und ja, mein Programm entziffert den Header (noch) nicht.
procedure TfrmMain.btnOpenClick(Sender: TObject);
var FS: TJclBufferedStream; I, J, K: Integer; Ch : Char; EndOfHeader: Boolean; High, Low: String; IsHigh: Boolean; Param: Integer; ParamTyp, ParamSCMStr: String; ini: TINIFile; begin if NOT OpenDialog.Execute then Exit; Code.Lines.Clear; EndOfHeader := False; IsHigh := False; try Code.Lines.BeginUpdate; FS := TJclBufferedStream.Create(TFileStream.Create(OpenDialog.FileName, fmOpenRead),True); ini := TINIFile.Create(ExtractFilePath(Application.ExeName)+'SASCM.ini'); I := 0; While I < FS.Size do begin Caption := FloatToStr(I DIV 1024); Application.ProcessMessages; FS.Read(Ch, SizeOf(Ch)); if IntToHex(Ord(Ch),2) = 'A4' then EndOfHeader := True; if NOT EndOfHeader then Code.Lines.Text := Code.Lines.Text + IntToHex(Ord(Ch),2) else begin If IsHigh then High := IntToHex(Ord(Ch),2) else Low := IntToHex(Ord(Ch),2); if isHigh then begin ParamSCMStr := ini.ReadString('main',LowerCase(High+Low),'0,'); ParamSCMStr := Copy(ParamSCMStr, Pos(',',ParamSCMStr)+1, Length(ParamSCMStr)); Code.Lines.Add(GetOP(High, Low, ParamSCMStr)); ParamSCMStr := ini.ReadString('main',LowerCase(High+Low),'0,'); ParamSCMStr := Copy(ParamSCMStr,1,Pos(',',ParamSCMStr)-1); for K := 1 to StrToInt(ParamSCMStr) do begin Application.ProcessMessages; FS.Read(Ch, SizeOf(Ch)); I := I + 1; Param := Ord(Ch); case Param of 01: begin Param := 4; ParamTyp := 'INT32'; end; 02: begin Param := 2; ParamTyp := 'GVAR'; end; 03: begin Param := 2; ParamTyp := 'LVAR'; end; 04: begin Param := 1; ParamTyp := 'INT8'; end; 05: begin Param := 2; ParamTyp := 'INT16'; end; 06: begin Param := 4; ParamTyp := 'FLOAT32'; end; 07: begin Param := 6; ParamTyp := 'GARRAY'; end; 08: begin Param := 6; ParamTyp := 'LARRAY'; end; 09: begin Param := 8; ParamTyp := 'STR8'; end; 10: begin Param := 2; ParamTyp := 'GSTR8'; end; 11: begin Param := 2; ParamTyp := 'LSTR8'; end; 12: begin Param := 6; ParamTyp := 'GSTRA8'; end; 13: begin Param := 6; ParamTyp := 'LSTRA8'; end; 14: begin FS.Read(Ch, SizeOf(Ch)); I := I + 1; Param := Ord(Ch); ParamTyp := 'USTR'; end; 15: begin Param := 16; ParamTyp := 'STR16'; end; 16: begin Param := 2; ParamTyp := 'GVSTR'; end; 17: begin Param := 2; ParamTyp := 'LVSTR'; end; 18: begin Param := 6; ParamTyp := 'GVSTRA'; end; 19: begin Param := 6; ParamTyp := 'LVSTRA'; end; else begin Param := 0; ParamTyp := ''; end; end; if ParamTyp <> '' then begin Code.Lines.Text := Code.Lines.Text + ParamTyp + ' '; for j := Param downto 1 do begin FS.Read(Ch, SizeOf(Ch)); I := I + 1; Code.Lines.Text := Code.Lines.Text + IntToHex(Ord(Ch),2)+' '; end; end; end; end; IsHigh := NOT IsHigh; end; I := I + 1; end; finally FS.Free; ini.Free; Code.Lines.EndUpdate; end; end; |
Re: TStrings ist *unglaublich* langsam
Das ist eine Bremse:
Delphi-Quellcode:
Jedes mal, wenn auf die Texteigenschaft zugegriffen wird, wird alles ausgelesen. Warum nimmst du nicht die Methode Add von Lines?
Code.Lines.Text := Code.Lines.Text + ParamTyp + ' ';
|
Re: TStrings ist *unglaublich* langsam
Zitat:
edit: Ok, vielen Dank. Dein Tipp hat hier wirklich geholfen und den Prozess um das 1000-fache beschleunigt. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:57 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz