Próbuję przeanalizować plik INI przy użyciu C ++. Jakieś wskazówki, jak najlepiej to osiągnąć? Czy powinienem używać narzędzi Windows API do przetwarzania plików INI (z którymi jestem całkowicie nieznany), rozwiązania typu open source, czy też próbować analizować je ręcznie?
89
Jeśli potrzebujesz rozwiązania wieloplatformowego, wypróbuj bibliotekę opcji programu Boost .
źródło
Nigdy nie analizowałem plików ini, więc nie mogę być zbyt szczegółowy w tej kwestii.
Ale mam jedną radę:
nie wymyślaj na nowo koła, o ile istniejący spełnia Twoje wymagania
http://en.wikipedia.org/wiki/INI_file#Accessing_INI_files
http://sdl-cfg.sourceforge.net/
http://sourceforge.net/projects/libini/
http://www.codeproject.com/KB /files/config-file-parser.aspx
Powodzenia :)
źródło
Jeśli już używasz Qt
QSettings my_settings("filename.ini", QSettings::IniFormat);
Następnie odczytaj wartość
my_settings.value("GroupName/ValueName", <<DEFAULT_VAL>>).toInt()
Istnieje wiele innych konwerterów, które konwertują wartości INI zarówno na typy standardowe, jak i typy Qt. Więcej informacji można znaleźć w dokumentacji Qt dotyczącej QSettings.
źródło
sync()
, co może być niespodzianką), a to niszczy komentarze i kolejność, w jakiej zmienne były zdefiniowane wcześniej ...Używam SimpleIni . Jest wieloplatformowy.
źródło
to pytanie jest trochę stare, ale opublikuję swoją odpowiedź. Testowałem różne klasy INI (możesz je zobaczyć na mojej stronie ), a także używam simpleIni, ponieważ chcę pracować z plikami INI zarówno w oknach, jak i winCE. Funkcja GetPrivateProfileString () systemu Windows działa tylko z rejestrem na winCE.
Dzięki simpleIni jest bardzo łatwy do odczytania. Oto przykład:
#include "SimpleIni\SimpleIni.h" CSimpleIniA ini; ini.SetUnicode(); ini.LoadFile(FileName); const char * pVal = ini.GetValue(section, entry, DefaultStr);
źródło
inih to prosty parser ini napisany w C, zawiera również opakowanie C ++. Przykładowe użycie:
#include "INIReader.h" INIReader reader("test.ini"); std::cout << "version=" << reader.GetInteger("protocol", "version", -1) << ", name=" << reader.Get("user", "name", "UNKNOWN") << ", active=" << reader.GetBoolean("user", "active", true) << "\n";
Autor ma również listę istniejących bibliotek tutaj .
źródło
Czy próbowałeś libconfig ; składnia bardzo podobna do JSON. Wolę to od plików konfiguracyjnych XML.
źródło
Jeśli interesuje Cię przenośność platformy, możesz również wypróbować Boost.PropertyTree. Obsługuje ini jako format trwałości, chociaż drzewo właściwości może mieć tylko 1 poziom głębokości.
źródło
O ile nie planujesz tworzyć aplikacji międzyplatformowej, najlepszym sposobem byłoby użycie wywołań interfejsu API systemu Windows. Po prostu zignoruj uwagę w dokumentacji interfejsu API, że jest udostępniana tylko w celu zapewnienia zgodności aplikacji 16-bitowych.
źródło
Może późna odpowiedź, ale warto znać opcje ... Jeśli potrzebujesz rozwiązania wieloplatformowego, zdecydowanie możesz wypróbować GLIB, jest to interesujące ... ( https://developer.gnome.org/glib/stable/glib- Parser-klucz-wartość-plik-parser.html )
źródło
Wiem, że to pytanie jest bardzo stare, ale natknąłem się na to, ponieważ potrzebowałem czegoś międzyplatformowego dla linuxa, win32 ... Napisałem funkcję poniżej, jest to pojedyncza funkcja, która może analizować pliki INI, mam nadzieję, że inni uznają ją za przydatną.
reguły i zastrzeżenia: buf do przeanalizowania musi być łańcuchem zakończonym znakiem NULL. Załaduj swój plik ini do tablicy znaków i wywołaj tę funkcję, aby go przeanalizować. nazwy sekcji muszą być otoczone nawiasami kwadratowymi [], na przykład [MySection], a także wartości i sekcje muszą zaczynać się w wierszu bez początkowych spacji. Sparsuje pliki z końcówkami linii Windows \ r \ n lub Linux \ n. Komentarze powinny zawierać # lub // i zaczynać się na górze pliku, żadne komentarze nie powinny być mieszane z danymi wejściowymi INI. Cytaty i znaczniki są obcinane z obu końców zwracanego ciągu. Spacje są przycinane tylko wtedy, gdy znajdują się poza ofertą. Łańcuchy nie muszą mieć cudzysłowów, a białe znaki są obcinane, jeśli brakuje cudzysłowów. Możesz także wyodrębnić liczby lub inne dane, na przykład jeśli masz zmiennoprzecinkową, po prostu wykonaj atof (ret) w buforze ret.
// -----note: no escape is nessesary for inner quotes or ticks----- // -----------------------------example---------------------------- // [Entry2] // Alignment = 1 // LightLvl=128 // Library = 5555 // StrValA = Inner "quoted" or 'quoted' strings are ok to use // StrValB = "This a "quoted" or 'quoted' String Value" // StrValC = 'This a "tick" or 'tick' String Value' // StrValD = "Missing quote at end will still work // StrValE = This is another "quote" example // StrValF = " Spaces inside the quote are preserved " // StrValG = This works too and spaces are trimmed away // StrValH = // ---------------------------------------------------------------- //12oClocker super lean and mean INI file parser (with section support) //set section to 0 to disable section support //returns TRUE if we were able to extract a string into ret value //NextSection is a char* pointer, will be set to zero if no next section is found //will be set to pointer of next section if it was found. //use it like this... char* NextSection = 0; GrabIniValue(X,X,X,X,X,&NextSection); //buf is data to parse, ret is the user supplied return buffer BOOL GrabIniValue(char* buf, const char* section, const char* valname, char* ret, int retbuflen, char** NextSection) { if(!buf){*ret=0; return FALSE;} char* s = buf; //search starts at "s" pointer char* e = 0; //end of section pointer //find section if(section) { int L = strlen(section); SearchAgain1: s = strstr(s,section); if(!s){*ret=0; return FALSE;} //find section if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain1;} //section must be at begining of a line! s+=L; //found section, skip past section name while(*s!='\n'){s++;} s++; //spin until next line, s is now begining of section data e = strstr(s,"\n["); //find begining of next section or end of file if(e){*e=0;} //if we found begining of next section, null the \n so we don't search past section if(NextSection) //user passed in a NextSection pointer { if(e){*NextSection=(e+1);}else{*NextSection=0;} } //set pointer to next section } //restore char at end of section, ret=empty_string, return FALSE #define RESTORE_E if(e){*e='\n';} #define SAFE_RETURN RESTORE_E; (*ret)=0; return FALSE //find valname int L = strlen(valname); SearchAgain2: s = strstr(s,valname); if(!s){SAFE_RETURN;} //find valname if(s > buf && (*(s-1))!='\n'){s+=L; goto SearchAgain2;} //valname must be at begining of a line! s+=L; //found valname match, skip past it while(*s==' ' || *s == '\t'){s++;} //skip spaces and tabs if(!(*s)){SAFE_RETURN;} //if NULL encounted do safe return if(*s != '='){goto SearchAgain2;} //no equal sign found after valname, search again s++; //skip past the equal sign while(*s==' ' || *s=='\t'){s++;} //skip spaces and tabs while(*s=='\"' || *s=='\''){s++;} //skip past quotes and ticks if(!(*s)){SAFE_RETURN;} //if NULL encounted do safe return char* E = s; //s is now the begining of the valname data while(*E!='\r' && *E!='\n' && *E!=0){E++;} E--; //find end of line or end of string, then backup 1 char while(E > s && (*E==' ' || *E=='\t')){E--;} //move backwards past spaces and tabs while(E > s && (*E=='\"' || *E=='\'')){E--;} //move backwards past quotes and ticks L = E-s+1; //length of string to extract NOT including NULL if(L<1 || L+1 > retbuflen){SAFE_RETURN;} //empty string or buffer size too small strncpy(ret,s,L); //copy the string ret[L]=0; //null last char on return buffer RESTORE_E; return TRUE; #undef RESTORE_E #undef SAFE_RETURN }
Jak używać ... przykład ....
char sFileData[] = "[MySection]\r\n" "MyValue1 = 123\r\n" "MyValue2 = 456\r\n" "MyValue3 = 789\r\n" "\r\n" "[MySection]\r\n" "MyValue1 = Hello1\r\n" "MyValue2 = Hello2\r\n" "MyValue3 = Hello3\r\n" "\r\n"; char str[256]; char* sSec = sFileData; char secName[] = "[MySection]"; //we support sections with same name while(sSec)//while we have a valid sNextSec { //print values of the sections char* next=0;//in case we dont have any sucessful grabs if(GrabIniValue(sSec,secName,"MyValue1",str,sizeof(str),&next)) { printf("MyValue1 = [%s]\n",str); } if(GrabIniValue(sSec,secName,"MyValue2",str,sizeof(str),0)) { printf("MyValue2 = [%s]\n",str); } if(GrabIniValue(sSec,secName,"MyValue3",str,sizeof(str),0)) { printf("MyValue3 = [%s]\n",str); } printf("\n"); sSec = next; //parse next section, next will be null if no more sections to parse }
źródło
Skończyło się na korzystaniu z inipp, o którym nie wspomniano w tym wątku.
https://github.com/mcmtroffaes/inipp
Była to implementacja z licencją MIT tylko na nagłówek, która była wystarczająco prosta, aby dodać do projektu i 4 linie do użycia.
źródło