Autor Beitrag
NOS
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 178
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Fr 02.03.18 09:45 
Hallo zusammen,

meine Software ist über die Jahre gewachsen und der Ladevorgang der Settings ist schon etwas länger geworden ... da ich auch Listen in den Settings habe stelle ich fest dass die Speicherung in einer INI Datei schon sehr langsam ist.

Nun würde ich gern wissen wie ihr eure Settings speichert und ob es eventuell sogar spezielle Compos für sowas gibt.

Grüße ins Forum,

Andreas

Moderiert von user profile iconChristian S.: Typo im Titel behoben
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10045
Erhaltene Danke: 1185

W2k .. W7pro .. W10ent
TP3 .. D7pro .. D10.1
BeitragVerfasst: Fr 02.03.18 10:20 
Moin!

user profile iconNOS hat folgendes geschrieben Zum zitierten Posting springen:
die Speicherung in einer INI Datei schon sehr langsam ist.
Du verwendest TMemIniFile? Das sollte eigentlich relativ schnell sein... :gruebel: (Oder nimmst du noch TIniFile?! :shock:)

XML geht auch, warum nicht. Man handelt sich damit aber auch diverse andere Probleme ein. Ganz soo schlecht, wie man INI immer wieder mal wahrnimmt, ist das gar nicht. Und in Punkto Performance sollte XML auch nicht grade ganz vorne liegen. :nixweiss:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.

Für diesen Beitrag haben gedankt: NOS
NOS Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 178
Erhaltene Danke: 2

Win XP, Win Vista Ultimate, Win 7 Ultimate
Delphi 10 - Seattle PRO
BeitragVerfasst: Fr 02.03.18 10:29 
Hallo Narses,

ich nutze noch das "alte" INIFile .. am schnellsten sind Listen mit gleicher Blockgröße die ich als Records in einem Filestream schreibe ... sowas ist ja leider bei normalen Settings nicht wirklich machbar ... vielleicht sollte ich mal auf TMemINIFile umstellen :-)

Mein Traum wäre ein Object oder ne Compo wo ich die Variablen in eine Struktur lege und diese dann automatisch über einen filestream in eine datei schreibt :-)

Thanks,

Andreas
Symbroson
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 381
Erhaltene Danke: 67

Raspbian, Ubuntu, Win10
C, C++, Python, JavaScript, Lazarus, Delphi7, Casio Basic
BeitragVerfasst: Fr 02.03.18 12:43 
Ich finde ja json am bequemsten. Das kann man auch problemlos selber machen

_________________
most good programmers do programming not because they expect to get paid or get adulation by the public, but because it's fun to program. (Linus Torvalds)

Für diesen Beitrag haben gedankt: NOS
doublecross
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 125
Erhaltene Danke: 23

Windows 7
C#; Visual Studio 2015
BeitragVerfasst: Fr 02.03.18 13:37 
Hi,

es kommt ganz auf das Programm an. In der Regel bevorzuge ich XML, da es sehr Flexibel (auch dank der Baunstruktur und Attributen) ist aber gleichzeitig noch lesbar bleibt, falls da mal jemand per Hand ran muss.
Aber Narses hat recht, so schlecht sind INIs nicht, wenn ich aber an meine frühen Projekte zurückdenke kann ich das von TIniFile nicht behaupten. Wenn ich mich recht entsinne schreibt es nämlich jedes mal, wenn du eine wert veränderst auf die Platte, wenn du also alle deine Settings durchittterierst, und setzt, dann schreibst du für jeden Einstellungspunkt einmal die komplette Datei, dass das langsam wird wundert mich gar nicht. Dann gar es bei tIniFile glaube ich noch eine recht greringe Maximalgroße für die INI-Datei. Beides in Kombination führte bei mir sehr schnell dazu tMemIniFile zu verwenden. Dort muss du zwar durch den Aufruf von UpdateFile immer selber sagen, wann die Datei geschrieben werden soll, aber dafür wird das auch nur in diesem Fall gemacht (idealerweise also nur 1x, auch wenn du alle einstellungen veränderst) und die Größenbeschränkung der Datei fällt auch. Von dem UpdateFile einmal abgesehen wird es aber genauso verwendet wir tIniFile, so dass es ein leichtes sein sollte dein Programm darauf umzustellen. Dein Problem müsste das auf jeden Fall beheben.
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2245
Erhaltene Danke: 418

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Sa 03.03.18 12:47 
Guten Tag NOS,

mir schwebt gerade eine Idee vor, eine XML-Klasse zu erstellen, die ähnlich aufgebaut sein wird, wie die INI-Klasse.
Deinem "Wunsch" entsprechend sollte sie auch Strukturen und Klassen de/serialisieren können.
Bin gespannt, ob mir das so gelingt wie gedacht.

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1151
Erhaltene Danke: 79

Win7
DXE2 Prof, Lazarus
BeitragVerfasst: Sa 03.03.18 15:28 
user profile iconFrühlingsrolle hat folgendes geschrieben Zum zitierten Posting springen:
mir schwebt gerade eine Idee vor, eine XML-Klasse zu erstellen, die ähnlich aufgebaut sein wird, wie die INI-Klasse....

Das habe ich mir vor ein paar Jahren mal angetan. Verwende ich noch immer fuer einfache Sachen.
Fuer alles andere verwende ich "single file" Datenbanken oder eine Tabelle die ich einfach aus einer CSV Datei laden kann.

_________________
Solange keine Zeile Code geschrieben ist, läuft ein Programm immer fehlerfrei.
Ich teste nicht, weil ich Angst habe Fehler zu finden.
Frühlingsrolle
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2245
Erhaltene Danke: 418

[Win NT] 5.1 x86 6.1 x64
[Delphi] 7 PE, 2006, 10.1 Starter, Lazarus - [C#] VS Exp 2012 - [Android API 15] VS Com 2015, Eclipse, AIDE - [C++] Builder 10.1
BeitragVerfasst: Sa 03.03.18 18:17 
.NET hat sowas schon intus. Und hier muss man sich ein wenig aushelfen.
Ich hab's nun halbfertig. Der Rest kommt spätestens morgen nach.

Nachtrag

Die fertige XML-klasse (an INI angelehnt) sieht nun so aus:

ausblenden volle Höhe 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:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
unit ufrXMLConfigFile;

interface

uses
  Classes, Forms, Graphics, SysUtils, XMLDoc, XMLIntf;

type
  TfrXMLConfigFile = class
  private
    FXMLDocument: TXMLDocument;
    FFileName: string;
    FFont: TFont;
    function GetCount: Integer;
    function GetVersion: Integer;
  public
    constructor Create(const AFileName: string); overload;
    constructor Create; overload;
    destructor Destroy; override;
    function ReadBoolean(const Section, Ident: string;
      const Default: Boolean): Boolean;
    function ReadColor(const Section, Ident: string;
      const Default: TColor): TColor;
    function ReadDate(const Section, Ident: string;
      const Default: TDateTime): TDateTime;
    function ReadDateTime(const Section, Ident: string;
      const Default: TDateTime): TDateTime;
    function ReadDouble(const Section, Ident: string;
      const Default: Double): Double;
    function ReadFont(const Section: string; Default: TFont): TFont;
    function ReadInteger(const Section, Ident: string;
      const Default: Integer): Integer;
    function ReadString(const Section, Ident, Default: string): string;
    function ReadTime(const Section, Ident: string;
      const Default: TDateTime): TDateTime;
    function SectionExists(const Section: string): Boolean;
    procedure Clear;
    procedure DeleteSection(const Section: string);
    procedure ReadSections(Strings: TStrings);
    procedure WriteBoolean(const Section, Ident: stringconst Value: Boolean);
    procedure WriteColor(const Section, Ident: stringconst Value: TColor);
    procedure WriteDate(const Section, Ident: stringconst Value: TDateTime);
    procedure WriteDateTime(const Section, Ident: string;
      const Value: TDateTime);
    procedure WriteDouble(const Section, Ident: stringconst Value: Double);
    procedure WriteFont(const Section: string; Value: TFont);
    procedure WriteInteger(const Section, Ident: stringconst Value: Integer);
    procedure WriteString(const Section, Ident, Value: string);
    procedure WriteTime(const Section, Ident: stringconst Value: TDateTime);
    property Count: Integer read GetCount;
    property Version: Integer read GetVersion;
  end;

implementation

const
  FR_XML_CONFIG_FILE_VER = 20180305;


function TfrXMLConfigFile.GetCount;
begin
  result := FXMLDocument.DocumentElement.ChildNodes.Count;
end;

function TfrXMLConfigFile.GetVersion: Integer;
begin
  result := FR_XML_CONFIG_FILE_VER;
end;

constructor TfrXMLConfigFile.Create(const AFileName: string);
begin
  inherited Create;
  FFont := TFont.Create;
  FXMLDocument := TXMLDocument.Create(Application);
  FXMLDocument.Options := [doNodeAutoIndent, doAttrNull];
  FXMLDocument.Active := true;
  FFileName := AFileName;

  if FileExists(FFileName) then
    FXMLDocument.LoadFromFile(FFileName) else
    FXMLDocument.AddChild(ExtractFileName(ChangeFileExt(FFileName, '')));
end;

constructor TfrXMLConfigFile.Create;
begin
  FFileName := ChangeFileExt(Application.ExeName, 'Config.xml');
  Create(FFileName);
end;

destructor TfrXMLConfigFile.Destroy;
begin
  FXMLDocument.SaveToFile(FFileName);
  FXMLDocument.Free;
  FFont.Free;
  inherited;
end;

function TfrXMLConfigFile.ReadBoolean(const Section, Ident: string;
  const Default: Boolean): Boolean;
begin
  result := Boolean(ReadInteger(Section, Ident, Ord(Default)));
end;

function TfrXMLConfigFile.ReadColor(const Section, Ident: string;
  const Default: TColor): TColor;
begin
  result := StringToColor(ReadString(Section, Ident, ColorToString(Default)));
end;

function TfrXMLConfigFile.ReadDate(const Section, Ident: string;
  const Default: TDateTime): TDateTime;
begin
  result := StrToDate(ReadString(Section, Ident, DateToStr(Default)));
end;

function TfrXMLConfigFile.ReadDateTime(const Section, Ident: string;
  const Default: TDateTime): TDateTime;
begin
  result := StrToDateTime(ReadString(Section, Ident, DateTimeToStr(Default)));
end;

function TfrXMLConfigFile.ReadDouble(const Section, Ident: string;
  const Default: Double): Double;
begin
  result := StrToFloat(ReadString(Section, Ident, FloatToStr(Default)));
end;

function TfrXMLConfigFile.ReadFont(const Section: string;
  Default: TFont): TFont;
begin
  if not Assigned(Default) then
    Default := FFont;

  FFont.Color := ReadColor(Section, 'FontColor', Default.Color);
  FFont.Name := ReadString(Section, 'FontName', Default.Name);
  FFont.Size := ReadInteger(Section, 'FontSize', Default.Size);
  FFont.Style := TFontStyles(Byte(ReadInteger(Section, 'FontStyle',
                                              Byte(Default.Style))));
  result := FFont;
end;

function TfrXMLConfigFile.ReadInteger(const Section, Ident: string;
  const Default: Integer): Integer;
begin
  result := StrToInt(ReadString(Section, Ident, IntToStr(Default)));
end;

function TfrXMLConfigFile.ReadString(const Section, Ident,
  Default: string): string;
var
  node: IXMLNode;
begin
  node := FXMLDocument.DocumentElement.ChildNodes.FindNode(Section);

  FXMLDocument.DocumentElement.ChildNodes.BeginUpdate;
  if Assigned(node) and node.HasAttribute(Ident) then
    result := node.Attributes[Ident] else
    result := Default;
  FXMLDocument.DocumentElement.ChildNodes.EndUpdate;
end;

function TfrXMLConfigFile.ReadTime(const Section, Ident: string;
  const Default: TDateTime): TDateTime;
begin
  result := StrToTime(ReadString(Section, Ident, TimeToStr(Default)));
end;

function TfrXMLConfigFile.SectionExists(const Section: string): Boolean;
begin
  result := Assigned(FXMLDocument.DocumentElement.ChildNodes.FindNode(Section));
end;

procedure TfrXMLConfigFile.Clear;
begin
  FXMLDocument.DocumentElement.ChildNodes.Clear;
end;

procedure TfrXMLConfigFile.DeleteSection(const Section: string);
var
  node: IXMLNode;
  idx: Integer;
begin
  node := FXMLDocument.DocumentElement.ChildNodes.FindNode(Section);
  idx := FXMLDocument.DocumentElement.ChildNodes.IndexOf(node);

  if idx > -1 then
    FXMLDocument.DocumentElement.ChildNodes.Delete(idx);
end;

procedure TfrXMLConfigFile.ReadSections(Strings: TStrings);
var
  node: IXMLNode;
  i: Integer;
begin
  node := FXMLDocument.DocumentElement;

  Strings.BeginUpdate;
  for i := 0 to node.ChildNodes.Count - 1 do
    Strings.Add(node.ChildNodes[i].NodeName);
  Strings.EndUpdate;
end;

procedure TfrXMLConfigFile.WriteBoolean(const Section, Ident: string;
  const Value: Boolean);
begin
  WriteString(Section, Ident, IntToStr(Ord(Value)));
end;

procedure TfrXMLConfigFile.WriteColor(const Section, Ident: string;
  const Value: TColor);
begin
  WriteString(Section, Ident, ColorToString(Value));
end;

procedure TfrXMLConfigFile.WriteDate(const Section, Ident: string;
  const Value: TDateTime);
begin
  WriteString(Section, Ident, DateToStr(Value));
end;

procedure TfrXMLConfigFile.WriteDateTime(const Section, Ident: string;
  const Value: TDateTime);
begin
  WriteString(Section, Ident, DateTimeToStr(Value));
end;

procedure TfrXMLConfigFile.WriteDouble(const Section, Ident: string;
  const Value: Double);
begin
  WriteString(Section, Ident, FloatToStr(Value));
end;

procedure TfrXMLConfigFile.WriteFont(const Section: string; Value: TFont);
begin
  WriteColor(Section, 'FontColor', Value.Color);
  WriteString(Section, 'FontName', Value.Name);
  WriteInteger(Section, 'FontSize', Value.Size);
  WriteInteger(Section, 'FontStyle', Byte(Value.Style));
end;

procedure TfrXMLConfigFile.WriteInteger(const Section, Ident: string;
  const Value: Integer);
begin
  WriteString(Section, Ident, IntToStr(Value));
end;

procedure TfrXMLConfigFile.WriteString(const Section, Ident, Value: string);
var
  node: IXMLNode;
begin
  node := FXMLDocument.DocumentElement.ChildNodes.FindNode(Section);

  if not Assigned(node) then
    node := FXMLDocument.DocumentElement.AddChild(Section);
  node.Attributes[Ident] := Value;
end;

procedure TfrXMLConfigFile.WriteTime(const Section, Ident: string;
  const Value: TDateTime);
begin
  WriteString(Section, Ident, TimeToStr(Value));
end;

end.

Beispiel:

ausblenden volle Höhe 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:
// SPEICHERN
var
  frXML: TfrXMLConfigFile;
begin
  frXML := TfrXMLConfigFile.Create();
  try
    with frXML do
    begin
      // Boolean
      WriteBoolean('Boolean''False', false);
      WriteBoolean('Boolean''True', true);
      // Color
      WriteColor('Color''TColor', clRed);
      WriteColor('Color''RGB', RGB(906090));
      WriteColor('Color''Hex'$906090);
      WriteColor('Color''Int'906090);
      // DateTime
      WriteDate('DateTime''Date', Now);
      WriteTime('DateTime''Time', Now);
      WriteDateTime('DateTime''DateTime', Now);
      // Sonstige
      WriteDouble('Sonstige''Double'90.609);
      WriteInteger('Sonstige''Integer'906090);
      WriteString('Sonstige''String''Text');
      WriteFont('Font', Button2.Font);
    end;
  finally
    frXML.Free
  end;
end;

// LADEN
var
  frXML: TfrXMLConfigFile;
begin
  frXML := TfrXMLConfigFile.Create();
  try
    with frXML do
    begin
      //Boolean
      CheckBox1.Checked := ReadBoolean('Boolean''False', false);
      CheckBox2.Checked := ReadBoolean('Boolean''True', false);
      // Color
      Panel1.Color := ReadColor('Color''TColor', clBlack);
      Panel2.Color := ReadColor('Color''RGB', RGB(000));
      Panel3.Color := ReadColor('Color''Hex'$0);
      Panel4.Color := ReadColor('Color''Int'0);
      // DateTime
      DateTimePicker1.Date := ReadDate('DateTime''Date'0);
      Caption := TimeToStr(ReadTime('DateTime''Time'0));
      DateTimePicker2.DateTime := ReadDateTime('DateTime''DateTime'0);
      // Sonstige
      Panel1.Caption := FloatToStr(ReadDouble('Sonstige''Double'0));
      Panel2.Caption := IntToStr(ReadInteger('Sonstige''Integer'0));
      Panel3.Caption := ReadString('Sonstige''String''');
      Panel4.Font := ReadFont('Font'nil);
    end;
  finally
    frXML.Free
  end;
end;

Ausgabe:

ausblenden XML-Daten
1:
2:
3:
4:
5:
6:
7:
<Project1Config>
  <Boolean False="0" True="1"/>
  <Color TColor="clRed" RGB="$005A3C5A" Hex="$00906090" Int="$000DD36A"/>
  <DateTime Date="06.03.2018" Time="03:56:19" DateTime="06.03.2018 03:56:19"/>
  <Sonstige Double="90,609" Integer="906090" String="Text"/>
  <Font FontColor="clBlue" FontName="Trebuchet MS" FontSize="16" FontStyle="3"/>
</Project1Config>

Sonstiges:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
.Clear;                         // Löscht alle Einträge
.DeleteSection('SomeSection');  // Löscht einen bestimmten Eintrag
.ReadSections(Memo1.Lines);     // Ermittelt alle Eintrags-Beschriftungen (ohne Werte) 
.SectionExists('SomeSection');  // Prüft, ob ein bestimmter Eintrag existiert
.Count;                         // Zählt alle Einträge

_________________
„Politicians are put there to give you the idea that you have freedom of choice. You don’t. You have no choice. You have owners. They own you. They own everything." (George Denis Patrick Carlin)


Zuletzt bearbeitet von Frühlingsrolle am Di 06.03.18 07:53, insgesamt 6-mal bearbeitet
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8400
Erhaltene Danke: 417

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.2 CE
BeitragVerfasst: So 04.03.18 13:49 
Für normale Einstellungen (Optionen, Fensterpositionen etc.) nutze ich TMemIniFile. Wenn längere Datensätze dazukommen, insbesondere Listen mit beliebiger Länge (d.h. der User kann beliebig Elemente hinzufügen), kommen diese Daten in eine weitere Datei mit einem dafür zugeschnittenen "Format".

Da mach ich dann oft einfach ein StringList.LoadFromFile und parse die schnell (d.h. ohne viel Code-Aufwand) selber. Entweder ein Item pro Zeile, ggf. in einem CSV-Format mit einem geeigneten Separator, oder pro String/Integer/etc. eine Zeile.

_________________
Oel ngati kameie.
Lemmy
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 789
Erhaltene Danke: 49

Windows 7 / 10; CentOS 7; LinuxMint
Delphi 7-XE10.1, VS 2015
BeitragVerfasst: Mo 05.03.18 07:37 
denkbar wäre auch JSON - vor allem wenn die Settings schon "fertig" in einer Delphi-Klasse zur Verfügung stehen. Sollte vermutlich auch nicht ganz langsam sein
Tankard
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 172
Erhaltene Danke: 29



BeitragVerfasst: Mo 05.03.18 17:00 
Also ich speicher die Sachen immer in einer SQLite3 Datei.
Schnell und flexibel.