Cómo se hace en C++: manejo de ficheros de configuración

Cómo se hace en C++: manejo de ficheros de configuración
Sin comentarios Facebook Twitter Flipboard E-mail

Continuamos con la serie de cómo se hace en C++. En la primera entrega recuerda que vimos cómo manejar ficheros XML con pugiXML. En esta segunda entrega vamos a ver como parsear y editar otro tipo de archivos comunes para almacenar datos. Se trata de los archivos de configuración que son con conocidos como archivos ini o archivos cfg.

Estructura de un archivo de configuración

Como ya hemos dicho los archivos de configuración suelen tener la extensión .ini ó .cfg y lo que se almacena en ellos son parejas de clave - valor. Además vienen divididos en varias secciones que agrupa un grupo de parámetros, lo mejor es verlo con un ejemplo.

[window] width=640 height=480 bpp=32 fullscreen=1

"#" Esto es un comentario, ignorado por el parseador.

[player] posx=14.6 posy=45.8 lives=5 name=Alex

Como vemos en este archivo tendríamos dos secciones una llamada window y otra llamada player y ambas contienen un grupo de parámetros separados por línea con un igual entre la clave y el valor. Los valores pueden ser cadenas de caracteres, enteros, números reales o variables booleanas.

Además podemos añadir comentarios a nuestro archivo para hacerlo más compresivo anteponiendo un ; o #. Estos comentarios son ignorados por el parseador.

Leyendo ficheros con inih

El proyecto inih es una pequeña biblioteca para parsear estos archivos ini y extraer la información. Es muy pequeña y rápida. Cuenta con una versión C y también con un wrapper para C++. Al ser una biblioteca tan pequeña lo más factible es integrar los propios archivos de cabecera e implementaciones en nuestro proyecto más que añadirlo como una biblioteca separada.

Su uso es tán sencillo como lo siguiente:

#include <iostream>
#include <string>
#include "INIReader.h"
int main()
{
INIReader file("prueba.ini");
if (file.ParseError() < 0) {
std::cout << "No se puede cargar prueba.ini" << std::endl;
return -1;
}
std::cout << file.GetInteger("window", "width", -1) << std::endl;
std::cout << file.GetInteger("window", "height", -1) << std::endl;
std::cout << file.GetInteger("window", "noExiste", -1) << std::endl;
if (file.GetBoolean("window", "fullscreen", false))
{
std::cout << "Pantalla Completa" << std::endl;
}
else
{
std::cout << "Modo ventana" << std::endl;
}
std::string nombre = file.Get("player", "name", "unknow");
std::cout << "Hola, " << nombre << std::endl;
float x = file.GetReal("player", "posx", 0);
float y = file.GetReal("player", "posy", 0);
std::cout << "Coordenadas: (" << x << ", " << y << ")" << std::endl;
system("pause");
return 0;
}
view raw main.cpp hosted with ❤ by GitHub

Como vemos después de importar los headers necesarios lo único que debemos hacer es crear un objeto del tipo INIReader y pasarle la ruta de nuestro fichero de configuración. El método ParseError nos devuelve un código menor que cero si no ha sido posible cargar el fichero.

Cuenta con solo 4 métodos más que son: Get, GetInteger, GetReal y GetBoolean. Estos cuatro métodos sirven para extraer los valores como cadena de texto (std::string), entero (long int), real (double) o Booleano (bool). Como vemos son siempre los tipos mayores de los diferentes tipos de datos para no perder información, si luego necesitamos menos siempre podemos hacer casting a int, float, etc.

Los métodos reciben 3 parámetros: El nombre de la sección, el nombre de la clave y el valor por defecto. El valor por defecto será el que se devuelva en caso de que no se encuentre al par clave-valor solicitado o que este no tenga un valor asignado.

Crear ficheros ini

Lamentablemente inih solo es un parseador de ficheros ini, si lo que queremos es modificarlo o crear uno debemos usar otras herramientas. Generar un archivo de configuración es tan trivial como crear un fichero de texto, así que podríamos hacer una clase pequeña para ello:

Archivo de cabecera

class ConfigCreate
{
public:
ConfigCreate();
~ConfigCreate();
void Open(const std::string& filename);
void Close();
void PutSection(const std::string& section);
void PutValue(const std::string& key, const std::string& value);
void PutComment(const std::string& comment);
void PutBlankLine();
private:
std::ofstream file;
}; // class ConfigCreate

Implementación

ConfigCreate::ConfigCreate()
{
}
ConfigCreate::~ConfigCreate()
{
}
void ConfigCreate::Open(const std::string& filename)
{
file.open(filename);
file.clear();
}
void ConfigCreate::Close()
{
file.close();
}
void ConfigCreate::PutSection(const std::string& section)
{
file << "[" << section << "]" << std::endl;
}
void ConfigCreate::PutValue(const std::string& key, const std::string& value)
{
file << key << "=" << value << std::endl;
}
void ConfigCreate::PutComment(const std::string& comment)
{
file << "# " << comment << std::endl;
}
void ConfigCreate::PutBlankLine()
{
file << std::endl;
}

Cuidado al crear un fichero sobreescribe otro preexistente, si lo que se quiere es modificar un archivo ini, primero usa un parser para obtener le contenido del fichero y luego generarlo de nuevo a partir de los valores obtenidos y los nuevos y/o modificados.

Su utilización sería de la siguiente manera.

ConfigCreate c;
c.Open("prueba.cfg");
c.PutSection("window");
c.PutValue("width", "640");
c.PutValue("height", "480");
c.PutComment("Activa la pantalla completa");
c.PutValue("fullscreen", "0");
c.PutBlankLine();
c.PutSection("Otra");
c.PutComment("lalalalala");
c.PutValue("djd", "edjie");
c.Close();
view raw main.cpp hosted with ❤ by GitHub

Esto generaría el siguiente fichero llamado prueba.cfg.

[window] width=640 height=480 "#" Activa la pantalla completa fullscreen=0

[Otra] "#" lalalalala djd=edjie

Más información | inih

Comentarios cerrados
Inicio
×

Utilizamos cookies de terceros para generar estadísticas de audiencia y mostrar publicidad personalizada analizando tu navegación. Si sigues navegando estarás aceptando su uso. Más información