Подтвердить что ты не робот

Как анализировать файл ini с помощью Boost

У меня есть ini файл, содержащий некоторые примерные значения, например:

[Section1]
Value1 = 10
Value2 = a_text_string

Я пытаюсь загрузить эти значения и распечатать их в своем приложении с помощью Boost, но я не понимаю, как это сделать на С++.

Я искал в этом форуме, чтобы найти несколько примеров (я всегда использовал C, и поэтому я не очень хорош в С++), но я нашел только примеры того, как читать значения из файла все сразу.

Мне нужно загрузить только одно значение, когда я хочу, например string = Section1.Value2, потому что мне не нужно читать все значения, но только некоторые из них.

Я хотел бы загрузить отдельные значения и сохранить их в переменной, чтобы использовать их, когда захочу в своем приложении.

Это можно сделать с помощью Boost?

На данный момент я использую этот код:

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

Но это просто прочитало все значения в цикле for; наоборот, я просто хочу читать одиночные значения, когда хочу, и мне не нужно вставлять значения в файл, потому что он уже написан со всеми значениями, которые мне нужны в моей программе.

4b9b3361

Ответ 1

Вы также можете использовать Boost.PropertyTree для чтения файлов .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;

Ответ 2

Анализ файлов INI легко из-за их простой структуры. Используя AX, я могу написать несколько строк для анализа разделов, свойств и комментариев:

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

Более подробный пример можно найти в Reference.pdf

Что касается не чтения всего файла, это можно сделать по-разному. Прежде всего, синтаксический анализатор для формата INI требует, по крайней мере, итераторов пересылки, поэтому вы не можете использовать итераторы потоков, поскольку они являются итераторами ввода. Вы можете создать отдельный класс для потока с требуемыми итераторами (я написал один такой класс в прошлом с скользящим буфером). Вы можете использовать файл с отображением памяти. Или вы можете использовать динамический буфер, чтение из стандартного потока и подачу на парсер до тех пор, пока не найдете значения. Если вы не хотите иметь настоящий синтаксический анализатор и не заботитесь, правильно ли структура файлов INI или нет, вы можете просто искать свои токены в файле. Для этого достаточно итераторов ввода.

Наконец, я не уверен, что избежать чтения всего файла принесет с собой какие-либо преимущества. Файлы INI, как правило, довольно малы, и поскольку жесткий диск и несколько буферизующих систем в любом случае будут читать один или несколько секторов (даже если вам нужен только один байт), поэтому я сомневаюсь, что будет какое-то улучшение производительности, пытаясь частично прочитать файл (особенно делая это многократно), возможно, наоборот.

Ответ 4

Файл нужно разобрать, что необходимо сделать последовательно. Поэтому я просто прочитал весь файл, сохранил все значения в некоторой коллекции (map или unordered_map, возможно, либо используя pair<section, key> в качестве ключа, либо используя карту карт) и вытащил их там, где это необходимо.