Sehr simple INI-File lesen
-
Hi,
ich grübel grad über nen schönen Weg eine INI-Datei zu lesen, also einfach eine Textdatei die im Format
; Zeilen mit ";" am Anfang sind Kommentare
setting1=wert
setting2=wertnur mit einigen Einschränkungen die das ganze noch viel einfacher machen. Ich kann nämlich schon vorher sagen dass keine Zeile länger als 48 Zeichen lang sein wird und dass es nur drei Einstellungen gibt, ich muss also nicht erst dynamisch speicher reservieren, ich kann einfach 3 vorgefertigte Variablen mit den Werten aus der INI füllen. Die drei einstellungen heißen
default_wlan_connection
default_server_ip
connect_on_startupDie Theorie dazu ist ganz simpel, aber ich hab ein paar praktische Fragen dazu:
int default_wlan_connection; int default_server_ip; int connect_on_startup; FILE *pINIfile; char iniLineBuffer[48]; char *valuePos; pINIfile = fopen("settings.ini" , "r"); while(fgets(iniLineBuffer, sizeof iniLineBuffer, pINIfile) != NULL) { if(iniLineBuffer[0] == ';') { continue; } else { valuePos = strchr(iniLineBuffer, '='); // Hier: iniLineBuffer bis zu position valuePos lesen und mit // den drei oben genannten Einstellungs-Namen vergleichen, nur // wie les ich nur bis Pos. X? // Und dann: Der Wert von "default_server_ip" kann unterschiedlich // lang sein. Wie les ich da bis zum Ende der Zeile? } }
Die Fragen stehen ja schon im Quellcode, aber abgesehen davon: Gibt es einen besseren Weg eine solche einfache INI-Datei zu lesen?
Grüße
Luke
-
erstmal: welche sprache?
in c++ kannst du boost::spirit nehmen oder wenn du die WinAPi verwendest einfach GetPrivateProfileString
Ansonsten:
- Eine Zeile aus Datei auslesen - erstes semikolon suchen, durch <strende> ersetzen, also zB line[semikolonpos] = 0; - leerzeichen vorne und hiten abschneiden (trim) - text an stelle '=' in zwei teile teilen. - Erster Teil mit deinen Schlüsseln vergleichen - Zweiten Teil in den schlüsselwert einschreiben. - nächste zeile lesen
So würde ich es machen
in c++ gibts es std::string für zeichenketten, mit operator ==, find usw.
Oder boost::spirit is aber ein bisschen overkillaber gut zum probieren. Oder boost::tokenizer, der splittet dir schnell deine zeiel bei allen =
-
Für INI-Files ist boost::spirit ja schon (fast) overkill.
Ich würde einfach mit std::getline die Zeile in einen std::string einlesen dadurch wird dein Code einfacher und du hast keine Längenbeschränkung mehr.
mit std::string::find_first_of kannst du nach dem ; in einer Zeile suchen und alles ab dem einfach löschen mit std::string::erase
mit std::string::find kannst du nach dem = suchen und dir den Substring davor und danach holen mit std::string::substrWenn du boost benutzt (ich geh mal nicht davon aus, da du C Funktionen benutzt) kannst du das ganze sogar noch einfacher machen mit den nützlichen boost::string_algos
-
Ja gut, C++ hab ich nicht (krieg ich auf meiner PSP im Moment nicht zum Kompilieren). Aber zu deiner Vorgehensweise: Wie Teilt man den String in zwei Teile?
-
Luke-2 schrieb:
Ja gut, C++ hab ich nicht (krieg ich auf meiner PSP im Moment nicht zum Kompilieren). Aber zu deiner Vorgehensweise: Wie Teilt man den String in zwei Teile?
Nichts leichter als das. Bedenke einfach nur, dass die Strings in C durch ein '\0' getrennt werden.
int main() { char foo[] = "hallo welt"; char *p = strchr(foo, ' '); if(!p) { fputs("Not Found!", stderr); return 1; } *p = '\0'; printf(Teil1: %s Teil2: %s\n", foo, p+1); }
-
Dieser Thread wurde von Moderator/in rüdiger aus dem Forum Rund um die Programmierung in das Forum ANSI C verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
rüdiger schrieb:
Nichts leichter als das. Bedenke einfach nur, dass die Strings in C durch ein '\0' getrennt werden.
Heh, ok. Ist ja wirklich einfach!
Danke!
-
Noch eine letzte Frage: Als zweites lese ich eine IP-Adresse (als Wert) mit aus der ini und speichere diesen mit strcpy(server_ip, p+1); in server_ip ab. Jetzt kommt es aber das server_ip (ein 16-byte-char-array) länger ist als die gelesene IP-Adresse. Wie stell ich es an an der richtigen stelle ein \0 einzufügen?
-
darum kümmert sich strcpy. Du musst nur darauf achten das man nicht mehr in server_ip reinkopieren kann, als in server_ip-Platz ist
-
lolz schrieb:
Für INI-Files ist boost::spirit ja schon (fast) overkill.
'boost' ist *immer* overkill, das zeug ist >600MB. stimmt das?
-
Hallo
Ich liebe einfach deine objektiven und ergebnisoffenen Antworten.
chrische
-
chrische5 schrieb:
Ich liebe einfach deine objektiven und ergebnisoffenen Antworten.
es war eine frage
-
pale dog schrieb:
lolz schrieb:
Für INI-Files ist boost::spirit ja schon (fast) overkill.
'boost' ist *immer* overkill, das zeug ist >600MB. stimmt das?
Bei Boost nimmt man ja eh nur das was man braucht.
-
Hallo
pale dog schrieb:
chrische5 schrieb:
Ich liebe einfach deine objektiven und ergebnisoffenen Antworten.
es war eine frage
Sorry, habe ich erst später gesehen. Obwohl sie auch wirklich provokativ gestellt war.
chrische
-
rüdiger schrieb:
darum kümmert sich strcpy. Du musst nur darauf achten das man nicht mehr in server_ip reinkopieren kann, als in server_ip-Platz ist
Ich benutze ja strcpy! Trotzdem ist bei der Ausgabe von server_ip ein Noten-Symbol und ein \n am Ende der Zeile.
Datei:
; Check the README for explanations on what the settings do
default_wlan_connection=1
default_server_ip=192.168.0.124
connect_on_startup=1Code:
pINIfile = fopen("settings.ini" , "r"); while(fgets(iniLineBuffer, sizeof iniLineBuffer, pINIfile) != NULL) { if(iniLineBuffer[0] == ';') { printf("Comment-line!\n"); } else { valueDelimiter = strchr(iniLineBuffer, '='); if(!valueDelimiter) { iniError = 1; continue; } *valueDelimiter = '\0'; if(strcmp(iniLineBuffer, "default_wlan_connection") == 0) { wlan_setting = atoi(valueDelimiter+1); printf("WLAN-Connection: %d\n", wlan_setting); } else if(strcmp(iniLineBuffer, "default_server_ip") == 0) { strcpy(server_ip, valueDelimiter+1); // Geht nicht ganz printf("Server-IP: %s\n", server_ip); } else if(strcmp(iniLineBuffer, "connect_on_startup") == 0) { connect_on_startup = atoi(valueDelimiter+1); printf("Auto-Connect: %d\n", connect_on_startup); } } } fclose(pINIfile);
Ausgabe:
Comment-line!
WLAN-Connection: 1
Server-IP: 192.168.0.124♪Auto-Connect: 1
-
Dieses "♪\n" ist ganz sicher ein "\r\n". Gibt es dafür in C (nicht++) nich ein trim oder so?
-
Wie gesagt. Ein String hört in C auf, sobald ein \0 gefunden wird...
-
Ich hab versucht die (womöglichen newlines und carriage-returns) manuell zu entfernen (auch wenn ich die lösung unschön finde), mit
[...] *valueDelimiter = '\0'; iniValue = valueDelimiter+1; if(strcmp(iniLineBuffer, "default_server_ip") == 0) { if(iniValue[sizeof(iniValue)] == '\n') iniValue[sizeof(iniValue)] = '\0'; if(iniValue[sizeof(iniValue)] == '\r') iniValue[sizeof(iniValue)] = '\0'; strcpy(server_ip, iniValue); printf("Server-IP: %s\n", server_ip); }
aber das funktioniert auch nicht. Kann ich da sizeof nicht so anwenden, bzw muss ich bei
iniValue = valueDelimiter+1;
richtig
*iniValue = valueDelimiter+1;
machen (ne, oder)?
Gibt es denn keine richtige trim-funktion?
-
sizeof() liefert die vorreservierte Größe des Arrays - und 'x[sizeof(x)]' liegt mit Sicherheit außerhalb des reservierten Bereiches. Das letzte Zeichen des tatsächlich eingetragenen Strings erreichst du mit 'x[strlen(x)-1]'.
-
Jo, funktioniert, danke.