Quelle est la manière la plus simple d'analyser un fichier INI en C ++?

89

J'essaye d'analyser un fichier INI en utilisant C ++. Avez-vous des conseils sur la meilleure façon d'y parvenir? Dois-je utiliser les outils de l'API Windows pour le traitement des fichiers INI (avec lesquels je ne suis absolument pas familier), une solution open-source ou tenter de l'analyser manuellement?

conmulligan
la source

Réponses:

112

Vous pouvez utiliser les fonctions de l'API Windows, telles que GetPrivateProfileString () et GetPrivateProfileInt () .

Joël Spolsky
la source
4
GetPrivateProfileInt () et d'autres fonctions ne sont pas recommandées par MSDN, car elles sont obsolètes et toujours fournies uniquement pour une compatibilité basique avec les systèmes 16 bits plus anciens. Au lieu de cela, utilisez une autre approche. msdn.microsoft.com/en-us/library/windows/desktop/…
Zdeno Pavlik
Ils sont obsolètes car MS ne veut plus que vous utilisiez des fichiers ini, ils sont toujours idéaux si vous voulez réellement lire ou écrire de tels fichiers.
Neil le
113

Si vous avez besoin d'une solution multiplateforme, essayez la bibliothèque d' options de programme de Boost .

Adam Mitz
la source
1
Je suggérerais aussi cette bibliothèque
varnie
21
c'est la voie à suivre, je ne comprends pas pourquoi les gens votent simplement pour une réponse pas si générale.
Ramadheer Singh
17
@Gollum, on dirait que Windows est une dépendance donnée. Utiliser la bibliothèque d'options du programme signifie prendre une autre dépendance. Parfois, ce n'est pas un gros problème, parfois ça l'est.
IJ Kennedy
5
@malat Je suis confus, je n'ai pas mentionné le vote négatif?
sjdowling le
2
Il essaie de lire un fichier INI existant. L'utilisation de boost n'est pas une réponse car elle utilise un format similaire à INI.
Lothar
16

J'utilise SimpleIni . C'est multiplateforme.

Harold Ekstrom
la source
SimpleIni est maintenant hébergé sur Github.
Richard Ye
15

Si vous utilisez déjà Qt

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

Puis lisez une valeur

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

Il existe de nombreux autres convertisseurs qui convertissent vos valeurs INI en types standard et en types Qt. Voir la documentation Qt sur QSettings pour plus d'informations.

Dat Chu
la source
Pas mal, bien que si vous apportez des modifications, ils les sauvegardent dans le fichier .ini sans vraiment vous le dire (c'est-à-dire les appels du destructeur sync(), ce qui peut être une surprise) et cela détruit les commentaires et l'ordre dans lequel les variables ont été définies précédemment ...
Alexis Wilke
8

cette question est un peu vieille, mais je posterai ma réponse. J'ai testé différentes classes INI (vous pouvez les voir sur mon site Web ) et j'utilise également simpleIni parce que je veux travailler avec des fichiers INI sur Windows et winCE. GetPrivateProfileString () de Windows fonctionne uniquement avec le registre sur winCE.

Il est très facile à lire avec simpleIni. Voici un exemple:

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

inih est un simple analyseur ini écrit en C, il est également livré avec un wrapper C ++. Exemple d'utilisation:

#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'auteur a également une liste des bibliothèques existantes ici .

nimcap
la source
4

Avez-vous essayé libconfig ; syntaxe très JSON. Je le préfère aux fichiers de configuration XML.

Christopher Lightfoot
la source
3

Si vous êtes intéressé par la portabilité de la plateforme, vous pouvez également essayer Boost.PropertyTree. Il prend en charge ini en tant que format de persistance, bien que l'arborescence des propriétés ne soit que d'un niveau de profondeur.

gast128
la source
2

À moins que vous ne prévoyiez de rendre l'application multiplateforme, l'utilisation des appels d'API Windows serait la meilleure solution. Ignorez simplement la note dans la documentation de l'API concernant la fourniture uniquement pour la compatibilité des applications 16 bits.

crashmstr
la source
0

Je sais que cette question est très ancienne, mais je suis tombée dessus parce que j'avais besoin de quelque chose de multiplateforme pour linux, win32 ... J'ai écrit la fonction ci-dessous, c'est une fonction unique qui peut analyser les fichiers INI, j'espère que d'autres le trouveront utile.

règles et mises en garde: buf à analyser doit être une chaîne terminée par NULL. Chargez votre fichier ini dans une chaîne de tableau de caractères et appelez cette fonction pour l'analyser. les noms de section doivent être entourés de [] crochets, comme ce [MaSection], les valeurs et les sections doivent également commencer sur une ligne sans espaces de début. Il analysera les fichiers avec Windows \ r \ n ou avec des fins de ligne Linux \ n. Les commentaires doivent utiliser # ou // et commencer en haut du fichier, aucun commentaire ne doit être mélangé avec les données d'entrée INI. Les guillemets et les graduations sont coupés des deux extrémités de la chaîne de retour. Les espaces ne sont coupés que s'ils sont en dehors du devis. Les chaînes ne doivent pas obligatoirement comporter de guillemets et les espaces sont coupés si des guillemets sont manquants. Vous pouvez également extraire des nombres ou d'autres données, par exemple si vous avez un float, effectuez simplement un atof (ret) sur le tampon 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
}

Comment utiliser ... exemple ...

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
}
12oclocker
la source
0

J'ai fini par utiliser inipp qui n'est pas mentionné dans ce fil.

https://github.com/mcmtroffaes/inipp

Était une implémentation d'en-tête sous licence MIT qui était assez simple pour être ajoutée à un projet et 4 lignes à utiliser.

user1867382
la source