Entwickler-Ecke
Dateizugriff - INI-Dateien schneller schreiben
LonghornUser - So 23.05.10 18:07
Titel: INI-Dateien schneller schreiben
Hallo,
ich habe im Moment das Problem, dass das Schreiben von INI-Dateien schon bei einer Größe von ~1KB knapp 1 Sekunde dauert. Wenn ich das ganze auf einem langsameren Rechner (Notebook) mache, dauert es schon 5-6 Sekunden.
Ist das normal?? Gibt es eine Möglichkeit, diesen Vorgang zu beschleunigen (etwa ein anderes Format)?
Danke!!
Ciao LHUser
jaenicke - So 23.05.10 18:21
Da machst du wohl etwas falsch, aber ohne Code kann da niemand etwas dazu sagen. :nixweiss:
Ich hatte jedenfalls damals als ich noch INIs verwendet habe auch größere in wenigen Millisekunden eingelesen oder erstellt. Die Frage ist aber wie, denn es gibt die API-Funktionen, die Delphikapselung dazu (beides deprecated, also veraltet markiert, da nur für Kompatibilität zu Windows 3.x noch vorhanden) und eigene Möglichkeiten.
Zum Vergleich: Das Einlesen von Registrydateien, die im Grunde ja auch nur INIs sind, schaffe ich mit ca. 30-90 MiB/s, je nach Festplattengeschwindigkeit...
// EDIT:
Ach ja: wenn dir Geschwindigkeit wichtig ist, warum benutzt du dann INI-Dateien?!?
Gausi - So 23.05.10 19:17
Ini-Dateien sind nicht zur Datenspeicherung da, aber ich habe auch einige im Bereich von einigen kb. Nutzt du TIniFile oder TMemIniFile? Letzteres arbeitet erstmal nur im Speicher, auf Platte muss explizit durch MyIni.UpdateFile geschrieben werden.
Hatte das Problem mal, als ich noch mit einer Diskette gearbeitet habe. Mit IniFile war das Laufwerk ne Minute am rödeln, mit TMemIniFile ging das recht flott. :D
hansa - So 23.05.10 19:32
| Zitat: |
| Hatte das Problem mal, als ich noch mit einer Diskette gearbeitet habe. Mit IniFile war das Laufwerk ne Minute am rödeln, mit TMemIniFile ging das recht flott. :D |
Dann hätteste mal einwandfreie Diskette nehmen sollen und keine mit zig Lesefehlern. :mrgreen:
Gausi - So 23.05.10 20:01
Lesen ging auch recht zügig, aber 200 mal Schreibzugriff auf ne Floppy war dann doch etwas doof. ;-)
LonghornUser - Mo 24.05.10 13:56
OK. Da ich auch denke, dass ich nur einen Fehler drin habe, der die Sache lang macht, hier mal der entsprechende (gekürzte) Quelltext:
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:
| procedure TForm1.Save(Filename:String); var ini:TIniFile; i,z,q,j,l:Integer; s1:string; begin
if FileExists(Filename) then DeleteFile(Filename); ini := TIniFile.Create(Filename); i := 0; z := 0; for i := 0 to ListView1.GetCount-1 do begin q := 1; s1 := ''; INC(z); ini.WriteString('Section'+inttostr(i+1),'Section', ListView1.Items[i].Caption); ini.WriteString('Section'+inttostr(i+1),'Key1', ListView1.Items[i].SubItems.Strings[0]);
if ListView1.Items[i].SubItems.Strings[0] = someString1 then begin if (Array1[i] <> '') and (Array1[i] <> someString2) then ini.WriteString('Section'+inttostr(i+1),'Key2',Array1[i]) else ini.WriteString('Section'+inttostr(i+1),'Key2',SomeString2); ini.WriteString('Section'+inttostr(i+1),'Key3',Array2[i]); ini.WriteString('Section'+inttostr(i+1),'Key4',Array3[i]); end;
if ListView1.Items[i].SubItems.Strings[0] = someString3 then if (Array3[i]<>'') and (Array3[i]<>someString4) then begin for j := 1 to length(Array3[i]) do begin if j MOD 100 = 0 then begin INC(q); s1 := ''; ini.WriteString('Section'+inttostr(i+1),'Key5_'+inttostr(q),s1); end; if Array3[i][j] <> '' then begin ini.WriteString('Section'+inttostr(i+1),'Count',inttostr(q)); s1 := s1 + Array3[i][j]; ini.WriteString('Section'+inttostr(i+1),'Key5_'+inttostr(q),s1); end; end; if q = 1 then begin ini.WriteString('Section'+inttostr(i+1),'Key5_1',s1); ini.WriteString('Section'+inttostr(i+1),'Count','1'); end; end else ini.WriteString('Section'+inttostr(i+1),'Key5',someString4);
end; ini.WriteInteger('SectionCount','Count',z); ini.Free; end; |
jaenicke - Mo 24.05.10 14:39
Der größte Fehler, der auf Anhieb klar ist, ist, dass die Daten offenbar nur in der TListView liegen. Und der Zugriff auf die visuellen Komponenten ist nun einmal langsam. Die Daten gehören dort nur angezeigt, mehr nicht...
Wenn du die Daten im Hintergrund in einer geeigneten Datenstruktur hältst, dann ist der Zugriff auch entsprechend schneller. Ansonsten ist die größte Bremse wohl die Benutzung von INIs selbst. Dass das soo langsam ist, hätte ich trotzdem nicht gedacht.
LonghornUser - Mo 24.05.10 16:16
Ich wollte ja mal BigIni ausprobieren, aber unter Delphi 2010 bekomme ich das ganze nicht zum Laufen (es kommen Fehler beim Kompilieren von BigIni.pas) :( Ob das was helfen würde?
Ich kann irgendwie nicht glauben, dass nur die Benutzung des ListViews soviel Zeit kosten soll (im Sekundenbereich) :?
Lannes - Mo 24.05.10 16:29
Hallo,
wenn ich das richtig sehe schreibt der Code bei jedem der 100 Zeichen immer wieder das gleiche in die ini:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| for j := 1 to length(Array3[i]) do begin if j MOD 100 = 0 then begin INC(q); s1 := ''; ini.WriteString('Section'+inttostr(i+1),'Key5_'+inttostr(q),s1); end; if Array3[i][j] <> '' then begin ini.WriteString('Section'+inttostr(i+1),'Count',inttostr(q)); s1 := s1 + Array3[i][j]; ini.WriteString('Section'+inttostr(i+1),'Key5_'+inttostr(q),s1); end; end; |
LonghornUser - Mo 24.05.10 16:48
Nö, das macht er eigentlich nicht. Ist vielleicht etwas kryptisch geschrieben, aber tut seinen Zweck :)
Aber vielleicht gibt es eine bessere Variante, einen Text in 100-Zeichen-Abschnitte zu zerteilen? Es hat sich nämlich gezeigt, dass genau dieser Abschnitt Probleme macht (der MOD-Abschnitt). Irgendetwas ist da ziemlich langsam.
jaenicke - Mo 24.05.10 17:12
So, ich habe es einmal getestet. Der Flaschenhals ist wie ich auch hauptsächlich dachte die INI-Nutzung. Beim Lesen aus der ListView ist diese (anders als ein Memo!!) nicht langsamer (das hätte ich nicht gedacht).
Zum Vergleich: Die normale Speicherung in einem eigenen Format dauert unter 15 Millisekunden für 1000 Einträge, bei einer INI sind es ca. 50 Sekunden...
LonghornUser - Mo 24.05.10 17:25
jaenicke hat folgendes geschrieben : |
So, ich habe es einmal getestet. Der Flaschenhals ist wie ich auch hauptsächlich dachte die INI-Nutzung. Beim Lesen aus der ListView ist diese (anders als ein Memo!!) nicht langsamer (das hätte ich nicht gedacht).
Zum Vergleich: Die normale Speicherung in einem eigenen Format dauert unter 15 Millisekunden für 1000 Einträge, bei einer INI sind es ca. 50 Sekunden... |
Danke für deine Mühe!! Das hätte ich nicht gedacht. Dabei speichere ich ja auch nicht wirklich viel. Sind wie gesagt vielleicht 1KB.
Das schaue ich mir nachher mal an, danke für den Tipp!
jaenicke - Mo 24.05.10 17:35
Ich habe es einmal mit TMemIniFile und TFastIniFile getestet. Die beiden sind nur etwa 7 bis 12 Mal langsamer als eine eigene Speicherung (100ms bis 150ms gegenüber 12-16ms). Die nehmen sich aber nicht viel, jedenfalls bei meinem Test waren die fast genauso schnell.
LonghornUser - Mo 24.05.10 18:10
Also kann ich praktisch auch das bereits in Delphi integrierte MemIni nehmen?
Edit: Ich habe es jetzt einfach mal mit TMemIniFile probiert und siehe da: Das Schreiben funktioniert wesentlich schneller.
Vielen Dank für eure Hilfe bis dahin!!!
Ist MemIniFile eigentlich auch beim Lesen schneller als IniFile?
jaenicke - Mo 24.05.10 18:33
Ich habe es nicht ausprobiert, aber ich denke ja, denn es basiert ja darauf, dass die Daten im Arbeitsspeicher gehalten werden.
Und wie gesagt: Mit einer eigenen Datenspeicherung hat man kleinere Datendateien, deutlich mehr Geschwindigkeit und einfacher ist es auch.
Lannes - Mo 24.05.10 22:50
Hallo,
LonghornUser hat folgendes geschrieben : |
| Nö, das macht er eigentlich nicht. |
dann gib mal zusätzlich die geschriebenen Ini-Werte in einem Memo aus.
Es ist richtig, der Code liefert im Ergebnis das was du willst, der letzte Schreibvorgang schreibt den Eintrag den du möchtest. Zuvor wird aber 100-mal der Ini-Eintrag überschrieben. Und da zwei Einträge geschrieben werden sind es 200 Schreibvorgänge.
LonghornUser - Di 25.05.10 13:00
Du hattest doch recht. Der Code (der unter uns gesagt mehrere Jahre alt ist ;)) war äußerst ineffizient.
Daher habe ich das ganze überarbeitet und dieser Code hier sollte mit deutlich weniger Schreibzugriffen auskommen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| for j := 0 to length(Array3[i]) div 100 do begin ini.WriteString('Section'+inttostr(i+1), 'Key5_'+inttostr(j+1), ''); ini.WriteString('Section'+inttostr(i+1), 'Key5_'+inttostr(j+1), Copy(Array3[i], j*100+1, 100)); ini.WriteString('Section'+inttostr(i+1), 'Count', inttostr(j+1)); end; |
Lannes - Di 25.05.10 18:57
LonghornUser hat folgendes geschrieben : |
| Du hattest doch recht. Der Code (der unter uns gesagt mehrere Jahre alt ist ;)) war äußerst ineffizient. |
ja, die Jugendsünden :wink:
Da sind immer noch überflüssige Schreibzugriffe und Berechnungen enthalten, teste mal den Code:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| var Sec: String; Count: Integer; begin Sec := 'Section' + IntToStr(Succ(i)); Count := Succ(Length(Array3[i]) div 100)); for j := 1 to Count do ini.WriteString(Sec, 'Key5_' + IntToStr(j), Copy(Array3[i], Pred(j)*100, 100)); ini.WriteString(Sec, 'Count', IntToStr(Count); |
LonghornUser - Di 25.05.10 19:08
Ja, das war eine ziemliche Jugendsünde ;)
Was genau sind denn Succ und Pred?
Lannes - Di 25.05.10 19:12
Succ = Nachfolger von einem ordinalen Datentyp
Pred = Vorgänger von einem ordinalen Datentyp
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!