¿Cuál es la forma más fácil de analizar un archivo INI en C++?
winapi fileparse (12)
Estoy tratando de analizar un archivo INI usando C ++. ¿Algún consejo sobre cuál es la mejor manera de lograr esto? ¿Debo usar las herramientas de la API de Windows para el procesamiento de archivos INI (que no conozco del todo), una solución de código abierto o intentar analizarla manualmente?
¿Has probado libconfig ? una sintaxis similar a JSON. Lo prefiero sobre los archivos de configuración XML.
A menos que planee hacer la aplicación multiplataforma, usar las llamadas API de Windows sería la mejor manera de hacerlo. Simplemente ignore la nota en la documentación de la API que se proporciona solo para la compatibilidad de aplicaciones de 16 bits.
Nunca he analizado archivos ini, así que no puedo ser demasiado específico en este tema.
Pero tengo un consejo:
No reinvente la rueda siempre que una existente cumpla con sus 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 :)
Puede usar las funciones de la API de Windows, como GetPrivateProfileString() y GetPrivateProfileInt() .
Sé que esta pregunta es muy antigua, pero me enteré porque necesitaba algo multiplataforma para Linux, Win32 ... escribí la función a continuación, es una función única que puede analizar archivos INI, ojalá que a otros les resulte útil.
rules & advertencias: buf to parse debe ser una cadena terminada NULL. Cargue su archivo ini en una cadena de matriz char y llame a esta función para analizarlo. los nombres de sección deben tener corchetes [] alrededor de ellos, como esta [MiSección], también los valores y las secciones deben comenzar en una línea sin espacios iniciales. Analizará archivos con Windows / r / n o con terminaciones de línea Linux / n. Los comentarios deben usar # o // y comenzar en la parte superior del archivo, no se deben mezclar los comentarios con los datos de entrada de INI. Las comillas y las señales se recortan desde ambos extremos de la cadena de retorno. Los espacios solo se recortan si están fuera de la cita. No se requiere que las cadenas tengan comillas, y los espacios en blanco se recortan si faltan las comillas. También puede extraer números u otros datos, por ejemplo, si tiene un flotador simplemente ejecute un atof (ret) en el 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
}
Cómo usar ... 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
}
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 ser solo de 1 nivel.
Si necesita una solución multiplataforma, pruebe la biblioteca de Opciones de Programa de Boost.
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 en tipos estándar y tipos Qt. Consulte la documentación de Qt en QSettings para obtener más información.
Tal vez 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 )
Yo uso SimpleIni . Es multiplataforma.
esta pregunta es un poco vieja, pero publicaré mi respuesta. He probado varias clases INI (puedes verlas en mi website ) y también uso simpleIni porque quiero trabajar con archivos INI en windows y winCE. Window GetPrivateProfileString () funciona solo 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 de ini simple escrito en C, viene con un envoltorio de C ++ también. Ejemplo de uso:
#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 here .