How to parse ini file with Boost

C++ParsingBoostIni

C++ Problem Overview


I have a ini file which contains some sample values like:

[Section1]
Value1 = 10
Value2 = a_text_string

I'm trying to load these values and print them in my application with Boost but I don't understand how to do this in C++.

I searched in this forum in order to find some examples (I always used C and so I'm not very good in C++) but I found only examples about how to read values from file all at once.

I need to load just a single value when I want, like string = Section1.Value2 because I don't need to read all the values, but just few of them.

I'd like to load single values and to store them in variable in order to use them when I want in my application.

It is possible to do this with Boost?

At the moment, I'm using this code:

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

But this just read all the values in a for loop; at the contrary I just want to read single values when I want and I don't need to insert values in the file, because it is already written with all the values which I need in my program.

C++ Solutions


Solution 1 - C++

You can also use Boost.PropertyTree to read .ini files:

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

Solution 2 - C++

Parsing INI files is easy due to their simple structure. Using AXE I can write in a few lines to parse sections, properties and comments:

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();

More detailed example can be found in the Reference.pdf

Regarding not reading the whole file, it can be done in different ways. First of all, parser for INI format requires at least forward iterators, so you can't use stream iterators, since they are input iterators. You can either create a separate class for stream with required iterators (I wrote one such class in the past with sliding buffer). You can use memory mapped file. Or you can use a dynamic buffer, reading from the standard stream and supplying to parser until you found the values. If you don't want to have a real parser, and don't care if the INI file structure is correct or not, you can simply search for your tokens in the file. Input iterators would suffice for that.

Finally, I'm not sure that avoiding reading the whole file brings any advantages with it. INI files are typically pretty small, and since the hard drive and multiple buffering systems would read one or more sectors anyway (even if you need just one byte), so I doubt there would be any performance improvement by trying to read file partially (especially doing it repeatedly), probably the opposite.

Solution 3 - C++

The file needs to be parsed, which has to be done sequentially. So I'd just read the whole file, store all the values in some collection (map or unordered_map, probably, either using pair<section, key> as key or using map of maps) and fetch them from there when needed.

Solution 4 - C++

I have read a nice article about INI-parsing with boost methods, it's called INI file reader using the spirit library by Silviu Simen.

It's simple one.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarcus BarnetView Question on Stackoverflow
Solution 1 - C++TimoView Answer on Stackoverflow
Solution 2 - C++Gene BushuyevView Answer on Stackoverflow
Solution 3 - C++Jan HudecView Answer on Stackoverflow
Solution 4 - C++mosgView Answer on Stackoverflow