Was sind heute gängige Verfahren, um Einstellung in einem simplen
Programm zu speichern (C++)?
InI Datei?
SQL Datenbank (z.B. eine kleine SQLite)?
Regedit? Was wäre das Pendant unter Linux?
Oder gibt es da inwzischen einfachere Lösungen?
Was sind "Einstellungen"? Wie viele, welche Komplexität haben diese
(sind das einfache numerische Werte, sind das komplexe Datenstrukturen
o.ä.), wie fehlertolerant darf/muss das Abspeichern/Einlesen sein,
welches Betriebssystem, welche Programmiersprache?
Sollen die "Einstellungen" auch transportiert werden können, oder
sollen/dürfen die auf dem individuellen Rechner verbleiben?
Eine Datenbank für (vermutlich) eine handvoll Einstellungen ist wohl
etwas over-the-top. Aber es gibt standardisierte Formate wie XML, YAML
oder JSON die weit verbreitet sind.
Max M. schrieb:> Regedit? Was wäre das Pendant unter Linux?
Das währe dann wohl gsettings/dconf (ehemals gconf). Ist aber eine reine
Gnome Geschichte, und nur für Benutzer-/Desktop- Anwendungen. Nicht alle
mögen es, die meisten Programme schreiben ihre Sachen einfach als File
in XDG_CONFIG_HOME
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
(Der Default ist normalerweise ~/.config/ für die User Settings und
/etc/xdg/ Systemweit) (Dort gibt es übrigens auch das dconf
Verzeichnis).
Max M. schrieb:> Was sind heute gängige Verfahren, um Einstellung in einem simplen> Programm zu speichern (C++)?
JSON-Dateien sind ganz vorne dabei, würde ich sagen. XML soll ja schon
wieder tot sein ... ;)
> InI Datei?
Kann man machen, ist aber manchmal dann doch zu einfach gestrickt.
> SQL Datenbank (z.B. eine kleine SQLite)?
Kanonen -> Spatzen.
> Regedit?
Würde ich eher nicht machen (es sei denn, es existieren sehr spezielle
Gründe dafür).
- Geht nicht unter Linux.
- Die Einstellungen können nicht einfach kopiert werden.
- Leichen können in der Registry verbleiben.
- ...
Schau dir das mal an:
https://github.com/nlohmann/json
Ist plattformunabhängig und man muss nur eine Headerdatei einbinden.
> Oder gibt es da inwzischen einfachere Lösungen?
Selber basteln würde ich das jedenfalls nicht mehr. Es muss ja nicht nur
irgendwie funktionieren, sondern sollte auch möglichst einfach und
elegant zu verwenden sein. Die Werte, die man speichern und einlesen
will, haben meist unterschiedliche Typen, was sich mit einer streng
typisierten Sprache u.U. etwas beißen kann ... Und dies ist nur eines
von mehreren Problemen, um die man sich kümmern muss. Das ist schon ein
kleines Projekt für sich, wenn man es vernünftig machen will.
Michael K. schrieb:> Ist plattformunabhängig und man muss nur eine Headerdatei einbinden.
Man sollte sich allerdings Gedanken darum machen, wo man die Datei
unterbringt. Das unterscheidet sich von Betriebssystem zu Betriebssystem
doch erheblich.
Die einfachste Lösung dürfte auch die älteste sein, der Inhalt des
relevanten Speicherbereichs wird binär so wie er ist in eine Datei
geschrieben, die beim Programmstart wieder in den Speicher geladen
werden kann.
Den ganzen anderen Quatsch braucht man nur wenn es für den Menschen
einfach lesbar sein soll oder man ein bestimmtes Dateiformat erzeugen
möchte, das möglicherweise kleiner wird als der abzubildende
Speicherbereich, etwa weil nicht alle Variablen eines Programms
gespeichert werden sollen.
Bzw. eine Initialisierungsdatei wie
1
Schalter1=an
2
Schalter2=aus
3
Schalter3=an
4
Schalter4=aus
5
Schalter5=an
6
Schalter6=aus
7
Schalter7=an
8
Schalter8=aus
hat für einen Computer genau so viel
Informations-Gehalt wie ein einzelnes Byte.
Ben B. schrieb:> Die einfachste Lösung dürfte auch die älteste sein, der Inhalt des> relevanten Speicherbereichs wird binär so wie er ist in eine Datei> geschrieben, die beim Programmstart wieder in den Speicher geladen> werden kann.
Funktioniert halt nur, wenn der "relevante Speicherbereich" so
strukturiert ist, daß er tatsächlich aus einem zusammenhängenden Block
besteht. Und hat den schönen Reiz, daß es knallt, falls die Struktur des
Speicherbereichs durch eine geänderte Programmversion verändert wird.
Ohne Versionierung ist so eine Binärdatei also eine leckere
Fehlerquelle.
Ben B. schrieb:> Den ganzen anderen Quatsch braucht man nur wenn es für den Menschen> einfach lesbar sein soll
Wenn da irgendein Mumpitz drinsteht, der die Anwendung gnadenlos
abstürzen läßt, dann ist man doch heilfroh, wenn man es editieren kann.
Binärdaten hat man vielleicht benutzt, als die Programme noch auf eine
160kB 5,25" Diskette passen mußten.
Zuerst wäre zu klären WO die Preferenzen gesichert werde sollen. Jedes
OS hat dafür m.W einen speziellen Systemordner, sowas wie
system.specialfolder.preferences (global) oder userspezifisch. Dann
gibts noch die Möglichgkeit, die Daten bei der Anwendung (im selben
Ordner) zu sichern. Das ist sinnvoll, wenn die Anwendung nicht speziell
"installiert" werden muss, sondern portable ist.
Ich habe mir für Xojo eine Preferences-Klasse selber gemacht, die kann
Integer, Double, String, Boolean und Color sichern und wieder laden. Der
Speicherort und der Name der Datei werden im Constructor übergeben.
Beim Sichern gehe ich ungefähr so vor:
mypref.addStr("dbname", dbname.text)
mypref.save (ganz am Ende)
also Key-Value-Prinzip.
Beim Laden entsprechend umgekehrt:
dbname.text = mypref.getStr("dbname")
Verschlüsseln tu' ich es nicht, aber mit Base64 gegen Encoding-Fehler
und all zu große Offensichtlichkeiten verpacken.
...
Er wollte eine möglichst einfache Möglichkeit wissen. Nichts für mehrere
verschiedene Programmversionen oder sonstige Übertragbarkeit.
> Wenn da irgendein Mumpitz drinsteht,> der die Anwendung gnadenlos abstürzen läßt [..]
Das ist kein Argument. Das kann bei einer .ini-Zeile wie
"Zahl=hahalustig" genau so passieren wenn das Programm nicht auf solche
Spaßvögel vorbereitet ist. Vielleicht kannst Du so einen Fehler noch
beheben weil Du Dich für die Programmierung interessierst und solche
Dateien lesen kann. Der 0815-Dau weiß aber nicht mal was eine .ini ist
und kommt gar nicht erst auf die Idee, sich das mal genauer anzuschauen.
Ben B. schrieb:> Das ist kein Argument. Das kann bei einer .ini-Zeile wie> "Zahl=hahalustig" genau so passieren wenn das Programm nicht auf solche> Spaßvögel vorbereitet ist.
Nö. Ini-Dateien werden (sofern man die dafür vorgesehenen API-Funktionen
verwendet) gezielt nach Key-Value-Paaren abgefragt. Wenn da zusätzliches
Geraffel drinsteht, stört das nicht, denn der wird gar nicht erst
gelesen.
Ein
Existiert die Datei nicht, steht in der Datei kein Abschnitt "Meinkram"
drin, gibt es keine Zeile "Meinwert=", gibt die Funktion den Wert 0
zurück.
Damit kann man ein sicheres Defaultverhalten herbeiführen, man muss nur
noch sicherstellen, daß der Wert insgesamt in einem sinnvollen
Wertebereich liegt.
Das aber ist's dann auch schon.
Und gespeichert wird das ganze so:
Das einzige, worum man sich kümmern muss, ist das Bestimmen des in den
Beispielen "meineinidatei" genannten Dateinamens und -Pfades.
Und man sollte einen Blick in die API-Dokumentation von MS reinwerfen.
Michael K. schrieb:> JSON-Dateien sind ganz vorne dabei, würde ich sagen.> XML soll ja schon wieder tot sein
JSON auch. Der neue heiße Scheiß sind YAML Dateien.
Eine Datenbank würde ich nur verwenden, wenn das Programm aus anderen
Gründen eh schon eine Datenbank hat. Ansonsten bin ich ein Freund von
Text-basierten Dateien, die man manuell bearbeiten kann, wenn es mal
sein muss.
Harald K. schrieb:> Was sind "Einstellungen"? Wie viele, welche Komplexität haben diese> (sind das einfache numerische Werte, sind das komplexe Datenstrukturen> o.ä.), wie fehlertolerant darf/muss das Abspeichern/Einlesen sein,> welches Betriebssystem, welche Programmiersprache?>> Sollen die "Einstellungen" auch transportiert werden können, oder> sollen/dürfen die auf dem individuellen Rechner verbleiben?
Nichts besonderes, das hätte ich ansonsten erwähnt. Vollkommener
Standard, Zahlen, Strings. Parameter z.B. für eine CNC o.ä.
Michael K. schrieb:> JSON-Dateien sind ganz vorne dabei, würde ich sagen. XML soll ja schon> wieder tot sein ... ;)
JSON finde ich persönlich ganz schlimm.
Im Endeffekt JSON, XML, INI, binär (ganz sicher nicht).
Vermutlich werde ich es ganz altmodisch mit ini versuchen.
Wo speichern denn Programme wie z.B. KiCad ihre Parameter?
Max M. schrieb:> Wo speichern denn Programme wie z.B. KiCad ihre Parameter?
Siehe Screenshot. Es sind überwiegend JSON Dateien, aber auch ein paar
andere.
Ich würde das auch in JSON machen, da es auch plattformübergreifend
(UTF-8) ist. Da gibt es bestimmt auch Libraries für C++ und Linux,
falls du mit Linux arbeitest.
Und viel schwerer, als mit einer .ini Datei ist es auch nicht.
Also für ein paar Einstellungen ideal. Dazu kommt noch, daß man
mit JSON Listen, deren Größe vorher noch unbestimmt ist, erzeugen
und erweitern kann.
{} = Objekt
[] = Liste
Für ein paar Einstellungen genügt da ein Haupt-Objekt und darin
die Werte : "Schlüssel" : Wert|"Wert"|BOOL
Also ganz einfach :
{"Maschine" : "Stand1", "Datum" : "27.04.2023", "Startwert" : 100,
"Parameter" : ["einString", 100, 0, 1]}
Wie man sieht, kann man in einer Liste auch Strings, Zahlen oder
boolsche
Werte mischen.
Dafür braucht man ja keine .zig Objekt-Ebenen zum Durchhangeln. Und
wenn man mehrere Maschinen hat, muß man halt zuerst ein oberes Objekt
(z.B. Maschinen) erzeugen und darin halt die Unterobjekte.
Mittlerweile arbeite ich ganz gerne mit JSON.
PS: Übrigens kannst du das auch mit SQLITE3 (Vers. 3.38) machen,
wenn deine Sprache SQL-Statements (SQLEXEC) unterstützt :
https://www.sqlite.org/json1.html
Back to the roots.
Die besten Zeiten waren die, wo man Programme einfach kopieren konnte,
also alle Einstellungen ebenfalls im gleichen Ordner wie das Programm
lagen.
wenn es keinen zwingenden Grund gibt, weil z.B. ANDERE Programme von der
Existenz deine Programms und womöglich dessen Optionen, wissen müssen,
gibt es gar keinen Grund und finde es sogar extrem Kontraproduktiv,
solche Informationen in irgendwelchen Registries abzulegen
Und wegen irgenwelcher Backup ist es ach ein wirkliches Argument
Für Einstellungen bevorzuge ich nach wie vor XML.
Das ist auch plattformübergreifend und hat vor allem den Vorteil, dass
man es einfach validieren kann. Mit XPath und XQuery sind auch einfache
Abfragen möglich.
Außerdem geben viele Editoren direkt Hinweise, wenn die Datei formal
nicht richtig ist, falls man die Daten einmal manuell korrigieren muss.
Dass es etwas größer ist als JSON, stört mich kaum. Die Dateien, um die
es bei mir geht, sind meistens recht klein (maximal ein paar kB), nur
wenige haben dann tatsächlich einmal mehrere MB. Ebenso kann ich gut
damit leben, dass XPath Abfragen nicht besonders performant sind - der
Komfortgewinn beim Programmieren gleicht das allemal aus; vor allem,
wenn diese Abfragen uim Programm nicht häufig benutzt werden (wie es bei
Konfigurationsdaten normalerweise der Fall ist).
> Nö. Ini-Dateien werden (sofern man die dafür vorgesehenen> API-Funktionen verwendet) gezielt nach Key-Value-Paaren abgefragt.> [..]
Das ist immer noch kein gutes Argument bzw. Du verlässt Dich halt auf
eine vorgefertigte API oder ein anderes Interface (wie auch z.B. ein
MySQL-Server eines wäre), was entsprechend gegen Vergewaltigung der
gespeicherten Daten gehärtet ist. Das kann man natürlich machen, aber
wenn man den Parser selbst schreibt oder ein eigenes Dateiformat
verwendet, muss man sich auch selbst um solche Fehlerquellen kümmern und
erlebt sehr merkwürdige Effekte, wenn man es nicht tut.
Peter K. schrieb:> Die besten Zeiten waren die, wo man Programme einfach kopieren konnte,> also alle Einstellungen ebenfalls im gleichen Ordner wie das Programm> lagen.
Das waren die schlimmsten Zeiten. Da hat jeder Hinz und Kunz
irgendwelchen Rotz irgendwo abgelegt, und man musste sich mühsam diesen
ganzen Krempel zusammensuchen, wenn man es auf einen anderen Rechner
übertragen wollte.
Das Konzept, alle von einem Benutzer erzeugten Dateien in einem
Verzeichnisbaum unterzubringen, der dem Benutzer gehört, ist da deutlich
besser -- dann können auch mehrere Leute mit einem Computer arbeiten,
ohne durcheinanderzukommen.
Wenn die Lebensabschnittsbegleiterin gerne ihre Textdokumente in "Comic
Sans" verfasst und die Standardformatvorlage so konfiguriert, muss man
sich nicht drüber ärgern, denn man hat seine eigene
Standardformatvorlage mit einer Schriftart für Erwachsene.
Heinz B. schrieb:> Ich würde das auch in JSON machen, da es auch plattformübergreifend> (UTF-8) ist. Da gibt es bestimmt auch Libraries für C++ und Linux,> falls du mit Linux arbeitest.
Mann muss dann einfach daran denken, dass man Binärdaten dann vorher
z.B. base64 Kodiert / Dekodiert. Und in C kann man Strings mit
beliebigen Byte folgen haben, z.B.
1
constcharmymessage[]="Hello\xFFWorld";
Wenn man das direkt als JSON String speichert, ist das \xFF kein
gültiges Zeichen. Vielleicht ist der Encoder noch so clever, es
wenigstens durch den Codepoint für ungültiges Zeichen zu ersetzen
(\xEF\xBF\xBD) oder so, statt ungültiges JSON zu erstellen, aber das
Zeichen so wieder Dekodieren wird nichts.
Ausserdem ist JSON eine Art Baumstruktur. Grafen, ala A.b=B B.a=A kann
man darin nicht direkt abbilden, das muss man dann auch manuell anders
darstellen.
Ja das ist auch so eine Unart, daß jeder sein eigenes Stringformat oder
Zeichensatz bis UTF-65536 benutzt nur weil er denkt, das wäre cool.
Deswegen bin ich bei meinen Datenbankprojekten schon lange dazu
übergegangen, solchen Quatsch einfach komplett "escaped" wegzuspeichern.
Wenn die search engine der Datenbank dann irgendwas nicht wiederfindet
weil mit solchen Sonderzeichen rumgespielt werden musste - nicht mein
Problem.
Ein Leerzeichen, wie man es für "Hello World!" benötigt, ist ASCII 32 -
und nicht 255. Keine Ahnung, wieso man in normalem Fließtext 255
benutzen sollte, außer man möchte das Programm ärgern.
Die meisten Datenbanken kennen einen VARBINARY(N) Datentyp, analog zum
VARCHAR(N). (Würde ich übrigens auch zum Speichern von Pfaden empfehlen,
die müssen nämlich nicht unbedingt normalisiertes UTF-8 sein). Und
analog zu TEXT gibt es BLOB.
In DBs escape ich nichts manuell. Da nimmt man die prepared Statements
die die DB Library anbietet, und die passenden Datentypen für die Daten.
PS: Bei sqlite ist sowieso alles immer schnuppe. Datentypen, Foreign
keys, etc. sind dort normalerweise nichts als blosse Suggestionen. Wobei
man aber wenigstens ein paar Checks einschalten kann.
Ben B. schrieb:> Keine Ahnung, wieso man in normalem Fließtext 255> benutzen sollte
Als Non-Breaking space, damit verhindert man Zeilenumbrüche im Fließtext
an Stellen an denen sie unerwünscht sind. Ist in UTF-8 allerdings nicht
255, sondern  .
Zum Thema zurück: Wenn der TE für sein C++ eine GUI-Bibliothek
verwendet, sollte er mal nachsehen, ob die nicht schon was passendes
mitbringt. z.B. https://doc.qt.io/qt-5/qsettings.html
Dann landen die Einstellungen auf jedem System in der dort üblichen Form
am dort üblichen Platz...
https://doc.qt.io/qt-5/qsettings.html#platform-specific-notes
Heinz B. schrieb:> Also ganz einfach :>> {"Maschine" : "Stand1", "Datum" : "27.04.2023", "Startwert" : 100,> "Parameter" : ["einString", 100, 0, 1]}
Das Selbe sieht in Yaml so aus:
1
Maschine: Stand1
2
Datum: 27.04.203
3
Startwert: 100
4
Parameter: [einString,100,0,1]
Oder alternativ so:
1
Maschine: Stand1
2
Datum: 27.04.203
3
Startwert: 100
4
Parameter:
5
- einString
6
- 100
7
- 0
8
- 1
Im Gegensatz zu JSON kann man YAML Dateien kommentieren.
Harald K. schrieb:> Das waren die schlimmsten Zeiten. Da hat jeder Hinz und Kunz> irgendwelchen Rotz irgendwo abgelegt, und man musste sich mühsam diesen> ganzen Krempel zusammensuchen, wenn man es auf einen anderen Rechner> übertragen wollte.
Nein, so war das garnicht. Alles lag halt innerhalb (unterhalb) des
Programmverzeichnisses.
Und es war sogar völlig problemlos möglich, benutzerspezifische
Einstellungen auf diese Art abzulegen. Ist nur ein Alptraum bezüglich
der Sicherheit und Vertraulichkeit. Bezüglich des reinen Datenflusses
geht das aber völlig problemlos.
> Das Konzept, alle von einem Benutzer erzeugten Dateien in einem> Verzeichnisbaum unterzubringen, der dem Benutzer gehört, ist da deutlich> besser
Natürlich erheblich besser bezüglich Sicherheit und Vertraulichkeit.
Aber führt auch einen Haufen Overhead ein. Da ist zum einen das Thema:
"Einstellungen, die ein User ABSICHTLICH (in guter Absicht!) mit
anderen Usern teilen möchte. Und zum anderen: Einstellungen, die eine
"übergeordnete Autorität" dem User unumgehbar aufzwingen möchte.
Beides läßt sich mit dem Konzept der Home-Verzeichnisse nur schlecht bis
garnicht abbilden.