.ini Files effizient verarbeiten



  • Hallo liebe Community,

    ich stehe zur Zeit mal wieder auf dem Schlauch. Ich muss in einem Programm diverse Konfigurationen einladen über die guten alten .ini Files. Leider stehen mir API Funktionen wie GetProfileString() nicht zur verfügung, weswegen ich meinen eigenen Parser geschrieben habe.

    Das letzte puzzlesteinchen, das verwalten der Schlüssel/Wertpaare fehlt mir jetzt allerdings noch. Ich bin mir nicht ganz sicher darüber, ib ich wirklich die kompletten Strings abspeichern soll und habe daher folgende Denkansätze entwickelt:

    • Erzeugung von Hashwerten aus den Schlüsseln, somit wäre jeder Schlüssel nurnoch 16 bzw. 32 bit groß. Dies verhindert allerdings das Zurückspeichern geänderter Werte
    • Speichern der Positionen im I/O Stream anstatt der Werte als string. Wie verhält es sich hier, wenn sich die Datei ändert, führt das eventuell zu Datenverlust/Datenmurks?
    • Cachen von einzelnen Sections und entladen wenn andere Section geladen wird. Performancetechnisch sicherlich nicht die beste Lösung, vor allem wenn man sehr große Sections hat

    Das ich std::map bzw. std::unordered_map verwenden muss sollte ja eigentlich klar sein, es sei denn jemand von euch weiß eine bessere Lösung oder generell eine Lösung für mein problem.

    Bin über Vorschläge dankbar!



  • Eine "normale" ini-Datei hat nicht genug Einträge, um sich den Kopf übers Hashen oder ähnliche Dinge zu zerbrechen. Von wie vielen Einträgen gehst du aus?

    Warum speicherst du sie überhaupt in einer Map ab? Ich würde beim Einlesen eher entsprechende Variablen mit dem Wert setzen.



  • Boost Spirit ist dein Freund! Da wird im folgenden Tutorial sogar ein ini-Parser mit gebaut:

    https://magazin.c-plusplus.net/artikel/Boost%3A%3ASpirit - Eine Einf�hrung

    Für gewöhnlich will man ja die Values verarbeiten. Die sollte man optimalerweise in einer Variable (die dem Key in einer Ini-Zeile entspricht) ablegen.

    Wenns keine Variablen gibt, dann halt in eine Map oder Vector gekapselt. Wenn du das hinter einer Facade versteckst, ist das ausreichend.

    Und warum willst du eine Hashmap implementieren? Kannst du keine Standard-C++-Library benutzen? Da ist doch schon alles drin.



  • Man kann in .ini Files IIRC, wenn man sie noch mit den Standard WinAPI Funktionen bearbeiten können möchte, gar keine besonders grossen Sections haben.
    Weil die Standard WinAPI Funktionen nämlich bei Pi*Daumen 64 kB (oder waren es 64k characters?) anfangen einfach (still und heimlich!) Unsinn zu bauen.

    Davon abgesehen...
    @Kalaeido
    WTF?

    Wie wär's mit "einfach alles in den Speicher schaufeln und gut is'"?

    ps:
    Wie man die Werte idealerweise in den Speicher packt wird auch davon abhängen ob es möglich sein soll/muss das .ini File anhand der im Speicher befindlichen Datenstruktur 1:1 zu rekonstruieren.
    Dazu müsste mann dann u.A. die exakte Reihenfolge der Sections/Werte rekonstruieren, Leerzeilen, Kommentare sowie auch so lustige Sachen wie

    [Section 1]
    Value1 = foo
    
    [Section 2]
    Value1 = bar
    
    ; Re-open Section 1
    [Section 1]
    Value2 = bar
    Value1 = and what shall we do with this???
    Foo = 42
    Bar = "42"
    

    p2:
    Ich würde einen Parser für .ini Files auf jeden Fall mit der Hand schreiben. Ist nicht wirklich schwer, und so hat man genaue Kontrolle über alles. D.h. man kann auch alles mögliche problemlos umsetzen, z.B. wie die eventuelle Forderung dass der Parser sämtliche Syntaxfehler und Abnormalitäten "verzeihen" soll.



  • Wenn windows.h zur verfügung steht, würde ich https://www.c-plusplus.net/forum/334277 einsetzen.

    Ansonsten gibt es auch TinyXML. http://www.grinninglizard.com/tinyxml2/



  • TinyXML kann .ini Files lesen? Cool! 🤡



  • hustbaer schrieb:

    Weil die Standard WinAPI Funktionen nämlich bei Pi*Daumen 64 kB (oder waren es 64k characters?) anfangen einfach (still und heimlich!) Unsinn zu bauen.

    Jetzt stell dich mal nicht so an, da läuft ja auch beim Einlesen das SI-Register über! 😃 ... wer kann den mit sowas rechnen???



  • hustbaer schrieb:

    Ich würde einen Parser für .ini Files auf jeden Fall mit der Hand schreiben. Ist nicht wirklich schwer, und so hat man genaue Kontrolle über alles. D.h. man kann auch alles mögliche problemlos umsetzen, z.B. wie die eventuelle Forderung dass der Parser sämtliche Syntaxfehler und Abnormalitäten "verzeihen" soll.

    +1

    Außerdem willste eh bald auch #include oder #ifdef können.



  • Hallo und vielen Dank für die Beiträge.

    Zunächst mal, ja die Files sind schon relativ riesig, da sind bis zu 8MB pro File schon drin weil es eifnach ein Haufen Settings sind, die ich nicht alle auf einmal benötige aber so nach und nach.

    Handelt sich dabei hauptsächlich um Konfigurationen verschiedener Plugins und Platformen so wie Tastenbelegungen, Einstellungen für diverse Programmbereiche wie z.b. das grafische Layout usw. Muss leider so abgelegt werden, da es mit zum Teil älteren "Standards" zusammenarbeiten muss bei denen das schon so gemacht wurde. Sonst hätte ich das auch alles in eine Binärdatei kodiert.

    Da das Zeug was in den .ini Files steht oft dynamisch mit dem Program zusammenpasst, ist die Idee mit den variablen zwar gut, lässt sich aber stellenweise nicht so ganz sauber umsetzen, da auch das "Speicherlayout" der Datei nicht immer ganz eundeutig ist, gerade wenn es um das Thema plugins geht.
    Werde ich aber auf jeden Fall in der Hinterhand behalten!

    WinAPI ist, hatte ich ja anfangs schon gesagt, keine Option weil noch andere Platformen involviert sind.

    TinyXML finde ich gut, da es aber ein ziemlicher Krampf wäre hunderte Zeilen ini in xml umzuschreiben (zumal XML meiner Meinung nach auch nicht das beste Format für soetwas ist), werden wir es wohl nicht integrieren. Dann eher noch Json 😃

    Einen Parser habe ich ja schon, der auch (relativ) handzahm ist und auch kleiner Syntaxfehler verzeiht, außerdem in der Lage ist auch direkt schon type identifizierung vorzunehmen, d.h. ich brauche die Werte nicht als string zu speichern, sondern kann das auch als Int, Float, Bool oder String machen.

    Gibt es in C++ zufällig eine Möglichkeit eine Datenstruktur zu identifizieren, also z.b. ich erzeuge einen container

    typedef struct UILayout
    {
       public:
          uint32_t BackgroundColor;
          uint32_t ForeColor;
          std::string BGImage;
          ...
    }UILayout;
    

    Und führe den dann der Funktion zu die mein ini File parst

    ...
    [Style]
    BackgroundColor = 0xff00ff
    ForeColor = 0x00fff0
    BGImage = My Images/Themes/default/background.png
    LeftHanded = 0
    ...
    
    UILayout style = UILayout();
    memset(&style, 0, sizeof(UILayout));
    
    if(myINIParser.Read("Style", &style))
       myWindow.SetStyle(&style);
    else
       myWindow.SetDefault();
    

    Sodas ich quasi immer einen bestimmten Satz an Feldern aus der Datei lesen würde, je nachdem welche Felder ich gerade haben möchte. Ich könnte mir auch vorstellen,d as z.b. mit caching zu kombinieren, dass ich vorher auch schon eine bestimmte Section vorladen kann aus der sich dann die Read methode bedienen kann 😕

    Nachtrag

    Löst aber mein Problem mit dem Zurückschreiben geänderter Werte in die Datei nicht wirklich



  • Kalaeido schrieb:

    Bin über Vorschläge dankbar!

    Das Thema hatten wir schon ein paar Mal - z.B.:
    - https://www.c-plusplus.net/forum/310564-full
    - https://www.c-plusplus.net/forum/308687-full

    boost hat auch was: http://www.boost.org/doc/libs/1_58_0/doc/html/program_options/overview.html (s. Configuration File Parser)



  • Auch bei den POCO C++ Libraries gibt es Klassen, um mit INI-Konfigurationsdateien umzugehen.
    Siehe Seite 6 von dieser Übersicht: http://pocoproject.org/slides/180-Configuration.pdf
    Und hier ist die entsprechende Klasse detaillierter beschrieben: http://pocoproject.org/docs/Poco.Util.IniFileConfiguration.html



  • Werner Salomon schrieb:

    Kalaeido schrieb:

    Bin über Vorschläge dankbar!

    Das Thema hatten wir schon ein paar Mal - z.B.:
    - https://www.c-plusplus.net/forum/310564-full
    - https://www.c-plusplus.net/forum/308687-full

    boost hat auch was: http://www.boost.org/doc/libs/1_58_0/doc/html/program_options/overview.html (s. Configuration File Parser)

    Die beiden Posts helfen mir nicht weiter. Auch hier werden wieder nur std::map<string,string> verwendet. Von boost halte ich entgegend er weitläufigen Meinung leider garnichts, ist für meinen einen Fall zu viel Müll mit dabei den ich nicht brauche.

    DonChunior schrieb:

    Auch bei den POCO C++ Libraries gibt es Klassen, um mit INI-Konfigurationsdateien umzugehen.
    Siehe Seite 6 von dieser Übersicht: http://pocoproject.org/slides/180-Configuration.pdf
    Und hier ist die entsprechende Klasse detaillierter beschrieben: http://pocoproject.org/docs/Poco.Util.IniFileConfiguration.html

    Ich hab mir die Lib mal angesehen und leider verwenden die leute auch hier entweder die WinAPI oder eben die genannte Konstellation aus std::map<string, string>



  • Kalaeido schrieb:

    Von boost halte ich entgegend er weitläufigen Meinung leider garnichts, ist für meinen einen Fall zu viel Müll mit dabei den ich nicht brauche.

    Verwegene Aussage von jemandem, der bei einem Ini-File Parser Hilfe braucht.



  • DocShoe schrieb:

    Verwegene Aussage von jemandem, der bei einem Ini-File Parser Hilfe braucht.

    Ich bin immer wieder fasziniert darüber, dass einige hier anscheinend nicht in der Lage sind den Startpost richtig zu lesen oder einfach gerade nur die letzten 2 Beiträge lesen und dann aber meinen ihren Senf dazu zu geben.

    Versteht mich nicht falsch, ich bin durchaus dankbar für Hilfe zu meinem Problem aber das Problem besteht im richtigen (speicher und zugriffszeit besten) Abspeichern der Werte aus dem ini File und nicht darin wie man ein ini File parst!

    Wie ich keine 3 Posts weiter oben bereits gesagt habe

    Einen Parser habe ich ja schon, der auch (relativ) handzahm ist und auch kleiner Syntaxfehler verzeiht, außerdem in der Lage ist auch direkt schon type identifizierung vorzunehmen, d.h. ich brauche die Werte nicht als string zu speichern, sondern kann das auch als Int, Float, Bool oder String machen

    Ich wollte aber wissen ob es effizientere Methoden gibt um die Wert/Schlüsselpaare abzuspeichern, im Programm zur Laufzeit zur verfügung zu haben als es mit std::map<string, string> im bezug auf die Speichergröße der Fall ist und habe auch diverse Ansätze genannt, die ich mir bis dato überlegt hatte, auch im Bezug auf sowohl reinholen ind as Programm, als auch wieder in die ini Datei zurück zu schreiben



  • Eine INI-Datei solltest du besser als Liste von Sektionen, welche wiederum aus einer Liste von Wertepaaren bestehen, modellieren:

    typedef std::vector<std::pair<std::string, std::string>> Section;
    
    typedef std:vector<Section> IniList;
    

    So erhältst du die Reihenfolge und kannst außerdem auch doppelte Einträge (und sogar Sektionen) erfassen.



  • Th69 schrieb:

    Eine INI-Datei solltest du besser als Liste von Sektionen, welche wiederum aus einer Liste von Wertepaaren bestehen, modellieren:

    typedef std::vector<std::pair<std::string, std::string>> Section;
    
    typedef std:vector<Section> IniList;
    

    So erhältst du die Reihenfolge und kannst außerdem auch doppelte Einträge (und sogar Sektionen) erfassen.

    Wieso nicht per map? Oder eben doppelter Map?

    typedef std::map<std::string, std::string> KeyValuePair;
    
    typedef std::map<std::string, KeyValuePair> GroupList;
    

Log in to reply