2011-05-30 12 views
57

Tengo un archivo ini que contiene algunos valores de la muestra como:Cómo analizar el archivo INI con Boost

[Section1] 
Value1 = 10 
Value2 = a_text_string 

que estoy tratando de cargar estos valores e imprimirlas en mi aplicación con Boost pero no lo hacen entender cómo hacer esto en C++.

He buscado en este foro para encontrar algunos ejemplos (siempre usé C y por eso no soy muy bueno en C++) pero solo encontré ejemplos sobre cómo leer valores de un archivo al mismo tiempo.

Necesito cargar un solo valor cuando quiero, como string = Section1.Value2 porque no necesito leer todos los valores, pero solo algunos de ellos.

Me gustaría cargar valores únicos y almacenarlos en variables para usarlos cuando quiera en mi aplicación.

¿Es posible hacer esto con Boost?

Por el momento, estoy usando este código:

#include <iostream> 
#include <string> 
#include <set> 
#include <sstream> 
#include <exception> 
#include <fstream> 
#include <boost/config.hpp> 
#include <boost/program_options/detail/config_file.hpp> 
#include <boost/program_options/parsers.hpp> 

namespace pod = boost::program_options::detail; 

int main() 
{ 
    std::ifstream s("file.ini"); 
    if(!s) 
    { 
     std::cerr<<"error"<<std::endl; 
     return 1; 
    } 

    std::set<std::string> options; 
    options.insert("Test.a"); 
    options.insert("Test.b"); 
    options.insert("Test.c"); 

    for (boost::program_options::detail::config_file_iterator i(s, options), e ; i != e; ++i) 
     std::cout << i->value[0] << std::endl; 
    } 

Pero esto acaba de leer todos los valores en un bucle for; por el contrario, solo quiero leer valores individuales cuando quiero y no necesito insertar valores en el archivo, porque ya está escrito con todos los valores que necesito en mi programa.

Respuesta

122

También puede utilizar Boost.PropertyTree para leer archivos .ini:

#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/ini_parser.hpp> 

... 

boost::property_tree::ptree pt; 
boost::property_tree::ini_parser::read_ini("config.ini", pt); 
std::cout << pt.get<std::string>("Section1.Value1") << std::endl; 
std::cout << pt.get<std::string>("Section1.Value2") << std::endl; 
+0

¡Excelente respuesta! Es lo que necesito para mi aplicación. Realmente muchas gracias! –

+0

¿Qué sucede si no conozco cierto conjunto de claves disponibles, pero aún quiero obtener una lista completa de pares clave = valor? Es decir. ¿Cómo reescribirías tu programa sin usar las constantes "Section1.Value1" y "Section1.Value2"? – javapowered

+0

upd: he encontrado esta pregunta http://stackoverflow.com/questions/11065938/boost-program-options-get-all-entries-in-section según que no sea posible sin escribir un código personalizado ... – javapowered

1

El archivo necesita ser analizado, lo cual tiene que hacerse secuencialmente. Así que acabo de leer todo el archivo, almacenar todos los valores en alguna colección (map o unordered_map, probablemente, ya sea usando pair<section, key> como clave o usando un mapa de mapas) y buscarlos desde allí cuando sea necesario.

3

archivos INI de análisis es fácil debido a su estructura simple. El uso de AX Puedo escribir en pocas líneas para analizar secciones, propiedades y comentarios:

auto trailing_spaces = *space & endl; 
auto section = '[' & r_alnumstr() & ']'; 
auto name = +(r_any() - '=' - endl - space); 
auto value = '"' & *("\\\"" | r_any() - '"') & '"' 
    | *(r_any() - trailing_spaces); 
auto property = *space & name & *space & '=' & *space 
    & value & trailing_spaces; 
auto comment = ';' & *(r_any() - endl) & endl; 
auto ini_file = *comment & *(section & *(prop_line | comment)) & r_end(); 

ejemplo más detallada se puede encontrar en el Reference.pdf

En cuanto a no leer todo el archivo, se puede hacer de diferentes formas. En primer lugar, el analizador para el formato INI requiere al menos iteradores hacia adelante, por lo que no puede usar iteradores de flujo, ya que son iteradores de entrada. Puede crear una clase separada para el flujo con los iteradores requeridos (escribí una de esas clases en el pasado con el buffer deslizante). Puede usar un archivo mapeado de memoria. O puede usar un búfer dinámico, leyendo de la secuencia estándar y suministrando al analizador hasta que encuentre los valores. Si no desea tener un analizador real, y no le importa si la estructura del archivo INI es correcta o no, simplemente puede buscar sus tokens en el archivo. Los iteradores de entrada serían suficientes para eso.

Finalmente, no estoy seguro de que evitar leer todo el archivo tenga alguna ventaja. Los archivos INI suelen ser bastante pequeños, y dado que el disco duro y los múltiples sistemas de almacenamiento en búfer leerían uno o más sectores de todos modos (incluso si necesita solo un byte), dudo que haya una mejora en el rendimiento al intentar leer el archivo parcialmente (especialmente haciéndolo repetidamente), probablemente lo contrario.

+0

+1 para la referencia de lo que parece ser una útil biblioteca de análisis para C++ 11: http://www.gbresearch.com/axe/ –

Cuestiones relacionadas