Pregunta

Estoy intentando analizar un archivo INI usando C++.¿Algún consejo sobre cuál es la mejor manera de lograrlo?¿Debo utilizar las herramientas API de Windows para el procesamiento de archivos INI (con las que no estoy totalmente familiarizado), una solución de código abierto o intentar analizarlo manualmente?

¿Fue útil?

Solución

Puede utilizar las funciones API de Windows, como Obtener cadena de perfil privado() y ObtenerPerfilPrivadoInt().

Otros consejos

Si necesita una solución multiplataforma, pruebe la de Boost Opciones del programa biblioteca.

Nunca he analizado archivos ini, por lo que no puedo ser demasiado específico sobre este tema.
Pero tengo un consejo:
No reinventes la rueda mientras una existente cumpla con tus requisitos

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

Buena suerte :)

yo suelo SimpleIni.Es multiplataforma.

Si ya estás usando Qt

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

Luego lee un valor

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

Hay muchos otros convertidores que convierten sus valores INI tanto en tipos estándar como en tipos Qt.Consulte la documentación de Qt en QSettings para obtener más información.

Esta pregunta es un poco antigua, pero publicaré mi respuesta.He probado varias clases INI (puedes verlas en mi sitio web) y también uso simpleIni porque quiero trabajar con archivos INI tanto en Windows como en WinCE.GetPrivateProfileString() de Windows sólo funciona con el registro en WinCE.

Es muy fácil de leer con simpleIni.Aquí hay un ejemplo:

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

inih es un analizador ini simple escrito en C, que también viene con un contenedor C++.Uso de ejemplo:

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

El autor también tiene una lista de bibliotecas existentes. aquí.

Has probado libconfig;sintaxis muy similar a JSON.Lo prefiero a los archivos de configuración XML.

Si está interesado en la portabilidad de la plataforma, también puede probar Boost.PropertyTree.Admite ini como formato de persistencia, aunque el árbol de propiedades puede tener solo 1 nivel de profundidad.

A menos que planee hacer que la aplicación sea multiplataforma, usar las llamadas a la API de Windows sería la mejor manera de hacerlo.Simplemente ignore la nota en la documentación de la API acerca de que se proporciona solo para compatibilidad de aplicaciones de 16 bits.

Quizás una respuesta tardía... Pero vale la pena conocer las opciones... Si necesita una solución multiplataforma, definitivamente puede probar GLIB, es interesante...(https://developer.gnome.org/glib/stable/glib-Key-value-file-parser.html)

Sé que esta pregunta es muy antigua, pero la encontré porque necesitaba algo multiplataforma para Linux, Win32...Escribí la función a continuación, es una función única que puede analizar archivos INI, espero que otros la encuentren útil.

reglas y advertencias:buf a analizar debe ser una cadena terminada en NULL.Cargue su archivo ini en una cadena de matriz de caracteres y llame a esta función para analizarlo.Los nombres de las secciones deben tener corchetes [] alrededor, como esta [MiSección], además los valores y las secciones deben comenzar en una línea sin espacios iniciales.Analizará archivos con terminaciones de línea Windows o Linux .Los comentarios deben usar # o // y comenzar en la parte superior del archivo; ningún comentario debe mezclarse con datos de entrada INI.Las comillas y los ticks se recortan de ambos extremos de la cadena de retorno.Los espacios sólo se recortan si están fuera del presupuesto.No es necesario que las cadenas tengan comillas y los espacios en blanco se recortan si faltan comillas.También puede extraer números u otros datos, por ejemplo, si tiene un flotante, simplemente realice un atof(ret) en el búfer 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
}

Cómo utilizar...ejemplo....

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
}

Terminé usando inipp que no se menciona en este hilo.

https://github.com/mcmtroffaes/inipp

Era una implementación de encabezado con licencia del MIT que era lo suficientemente simple como para agregarla a un proyecto y tenía 4 líneas para usar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top