Qual è il modo più semplice per analizzare un file INI in C ++?


89

Sto cercando di analizzare un file INI utilizzando C ++. Qualche consiglio su qual è il modo migliore per ottenere questo risultato? Devo usare gli strumenti API di Windows per l'elaborazione dei file INI (con cui non ho familiarità), una soluzione open source o tentare di analizzarla manualmente?

Risposte:


112

È possibile utilizzare le funzioni API di Windows, come GetPrivateProfileString () e GetPrivateProfileInt () .


4
GetPrivateProfileInt () e altre funzioni non sono consigliate da MSDN, perché sono obsolete e ancora fornite solo per la compatibilità baskward con i vecchi sistemi a 16 bit. Invece di usare un altro approccio. msdn.microsoft.com/en-us/library/windows/desktop/…
Zdeno Pavlik

Sono obsoleti perché MS non vuole più che tu usi i file ini, sono comunque ideali se vuoi effettivamente leggere o scrivere tali file.
Neil

114

Se hai bisogno di una soluzione multipiattaforma, prova la libreria Opzioni programma di Boost .


1
Suggerirei anche questa libreria
varnie

22
questa è la strada da percorrere, non capisco perché le persone si limitano a votare una risposta non così generale.
Ramadheer Singh

18
@ Gollum, sembra che Windows sia una determinata dipendenza. Usare la libreria Opzioni programma significa assumere un'altra dipendenza. A volte non è un grosso problema, a volte lo è.
IJ Kennedy,

5
@malat Sono confuso, non ho menzionato il downvoting?
sjdowling

2
Sta cercando di leggere un file INI esistente, L'uso di boost non è una risposta perché utilizza un formato simile a INI.
Lothar


16

Se stai già usando Qt

QSettings my_settings("filename.ini", QSettings::IniFormat);

Quindi leggi un valore

my_settings.value("GroupName/ValueName", <<DEFAULT_VAL>>).toInt()

Esistono molti altri convertitori che convertono i valori INI sia in tipi standard che in tipi Qt. Consultare la documentazione Qt su QSettings per ulteriori informazioni.


Non male, anche se se apporti delle modifiche le salvano di nuovo nel file .ini senza dirti davvero (cioè le chiamate del distruttore sync(), che può essere una sorpresa) e questo distrugge i commenti e l'ordine in cui le variabili sono state definite in precedenza ...
Alexis Wilke


8

questa domanda è un po 'vecchia, ma posterò la mia risposta. Ho testato varie classi INI (puoi vederle sul mio sito web ) e uso anche simpleIni perché voglio lavorare con file INI sia su windows che su winCE. GetPrivateProfileString () di Windows funziona solo con il registro su winCE.

È molto facile da leggere con simpleIni. Ecco un esempio:

#include "SimpleIni\SimpleIni.h"    
CSimpleIniA ini;
ini.SetUnicode();
ini.LoadFile(FileName);
const char * pVal = ini.GetValue(section, entry, DefaultStr);

6

inih è un semplice parser ini scritto in C, viene fornito anche con un wrapper C ++. Utilizzo di esempio:

#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";

L'autore ha anche un elenco delle biblioteche esistenti qui .



3

Se sei interessato alla portabilità della piattaforma, puoi anche provare Boost.PropertyTree. Supporta ini come formato di persistenza, sebbene l'albero delle proprietà sia profondo solo 1 livello.


2

A meno che non si preveda di rendere l'app multipiattaforma, l'utilizzo delle chiamate API di Windows sarebbe il modo migliore per procedere. Ignora semplicemente la nota nella documentazione dell'API sull'essere fornito solo per la compatibilità delle app a 16 bit.



0

So che questa domanda è molto vecchia, ma mi sono imbattuto perché avevo bisogno di qualcosa di multipiattaforma per Linux, win32 ... Ho scritto la funzione di seguito, è una singola funzione che può analizzare i file INI, spero che altri la troveranno utile.

regole e avvertenze: buf da analizzare deve essere una stringa terminata con NULL. Carica il tuo file ini in una stringa di array di caratteri e chiama questa funzione per analizzarlo. i nomi delle sezioni devono contenere [] parentesi quadre, come questa [MySection], inoltre i valori e le sezioni devono iniziare su una riga senza spazi iniziali. Analizzerà i file con Windows \ r \ no con terminazioni di riga Linux \ n. I commenti devono utilizzare # o // e iniziare all'inizio del file, nessun commento deve essere mischiato con i dati di immissione INI. Virgolette e segni di graduazione vengono tagliati da entrambe le estremità della stringa di ritorno. Gli spazi vengono tagliati solo se sono al di fuori della citazione. Le stringhe non devono contenere virgolette e gli spazi bianchi vengono tagliati se mancano virgolette. Puoi anche estrarre numeri o altri dati, ad esempio se hai un float basta eseguire un atof (ret) sul buffer 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
}

Come usare ... esempio ....

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
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.