Создание простого файла конфигурации и анализатора в С++
Я пытаюсь создать простой файл конфигурации, который выглядит как
url = http://mysite.com
file = main.exe
true = 0
когда программа запускается, я хотел бы загрузить параметры конфигурации в перечисленные ниже программные переменные.
string url, file;
bool true_false;
Я провел некоторое исследование и эта ссылка, казалось, помогла (нуклонная почта), но я не могу заставить ее работать, и это слишком сложно понять с моей стороны. Есть ли простой способ сделать это? Я могу загрузить файл с помощью ifstream
, но это насколько я могу получить сам. Спасибо!
Ответы
Ответ 1
В общем, проще всего разобрать такие типичные файлы конфигурации в два этапа: сначала прочитать строки, а затем разобрать их по одному.
В С++ строки могут быть прочитаны из потока с помощью std::getline()
. Хотя по умолчанию он будет читать до следующего '\n'
(который он будет использовать, но не будет возвращен), вы можете передать ему и другой разделитель, что делает его хорошим кандидатом для чтения до некоторых-char, например =
в вашем примере.
Для простоты следует, что =
не окружены пробелами. Если вы хотите разрешить пробелы на этих позициях, вам нужно стратегически разместить is >> std::ws
перед чтением значения и удалить завершающие пробелы из ключей. Тем не менее, IMO немного добавила гибкость в синтаксисе, не стоит хлопот для чтения файлов конфигурации.
const char config[] = "url=http://example.com\n"
"file=main.exe\n"
"true=0";
std::istringstream is_file(config);
std::string line;
while( std::getline(is_file, line) )
{
std::istringstream is_line(line);
std::string key;
if( std::getline(is_line, key, '=') )
{
std::string value;
if( std::getline(is_line, value) )
store_line(key, value);
}
}
(Добавление обработки ошибок остается как упражнение для читателя.)
Ответ 2
Как отмечали другие, вероятно, будет меньше работы, чтобы использовать существующую библиотеку анализатора конфигурационных файлов, а не повторно изобретать колесо.
Например, если вы решите использовать библиотеку Config4Cpp (которую я поддерживаю), ваш синтаксис файла конфигурации будет немного отличаться (put двойные кавычки вокруг значений и завершение операторов присваивания точкой с запятой), как показано в следующем примере:
# File: someFile.cfg
url = "http://mysite.com";
file = "main.exe";
true_false = "true";
Следующая программа анализирует вышеуказанный файл конфигурации, копирует нужные значения в переменные и печатает их:
#include <config4cpp/Configuration.h>
#include <iostream>
using namespace config4cpp;
using namespace std;
int main(int argc, char ** argv)
{
Configuration * cfg = Configuration::create();
const char * scope = "";
const char * configFile = "someFile.cfg";
const char * url;
const char * file;
bool true_false;
try {
cfg->parse(configFile);
url = cfg->lookupString(scope, "url");
file = cfg->lookupString(scope, "file");
true_false = cfg->lookupBoolean(scope, "true_false");
} catch(const ConfigurationException & ex) {
cerr << ex.c_str() << endl;
cfg->destroy();
return 1;
}
cout << "url=" << url << "; file=" << file
<< "; true_false=" << true_false
<< endl;
cfg->destroy();
return 0;
}
Сайт Config4Cpp содержит подробную документацию, но чтение только глав 2 и 3 "Руководства по началу работы" должно быть более чем достаточно для вашего необходимо.
Ответ 3
Наивный подход может выглядеть так:
#include <map>
#include <sstream>
#include <stdexcept>
#include <string>
std::map<std::string, std::string> options; // global?
void parse(std::istream & cfgfile)
{
for (std::string line; std::getline(cfgfile, line); )
{
std::istringstream iss(line);
std::string id, eq, val;
bool error = false;
if (!(iss >> id))
{
error = true;
}
else if (id[0] == '#')
{
continue;
}
else if (!(iss >> eq >> val >> std::ws) || eq != "=" || iss.get() != EOF)
{
error = true;
}
if (error)
{
// do something appropriate: throw, skip, warn, etc.
}
else
{
options[id] = val;
}
}
}
Теперь вы можете получить доступ к каждому значению параметра из глобальной карты options
в любом месте вашей программы. Если вы хотите использовать кастимость, вы можете сделать сопоставленный тип a boost::variant
.
Ответ 4
libconfig очень просто, и что лучше, он использует нотацию псевдо-json для лучшей читаемости.
Простота установки на Ubuntu: sudo apt-get install libconfig++8-dev
и ссылка: -lconfig++
Ответ 5
Почему бы не попробовать что-то простое и удобное для чтения, например JSON (или XML)?
Есть много готовых реализаций с открытым исходным кодом JSON (или XML) для С++ - я бы использовал один из них.
И если вы хотите что-то более "двоичное" - попробуйте BJSON или BSON:)
Ответ 6
Я недавно искал библиотеки для разбора текста для моего проекта и нашел эти библиотеки:
Ответ 7
Как насчет форматирования вашей конфигурации как JSON и использования библиотеки, например jsoncpp?
например.
{"url": "http://mysite dot com",
"file": "main.exe",
"true": 0}
Затем вы можете прочитать его в именованных переменных или даже сохранить все на карте std:: и т.д. Последнее означает, что вы можете добавлять параметры без необходимости изменять и перекомпилировать парсер конфигурации.
Ответ 8
Вот простая работа вокруг пробела между знаком "=" и данными в файле конфигурации. Присвоите значение istringstream из местоположения после знака '=', и при чтении из него игнорируется любое ведущее белое пространство.
Примечание: во время использования istringstream в цикле убедитесь, что вы вызываете clear() перед назначением ему новой строки.
//config.txt
//Input name = image1.png
//Num. of rows = 100
//Num. of cols = 150
std::string ipName;
int nR, nC;
std::ifstream fin("config.txt");
std::string line;
std::istringstream sin;
while (std::getline(fin, line)) {
sin.str(line.substr(line.find("=")+1));
if (line.find("Input name") != std::string::npos) {
std::cout<<"Input name "<<sin.str()<<std::endl;
sin >> ipName;
}
else if (line.find("Num. of rows") != std::string::npos) {
sin >> nR;
}
else if (line.find("Num. of cols") != std::string::npos) {
sin >> nC;
}
sin.clear();
}
Ответ 9
Я искал что-то, что работает как модуль Python ConfigParser и нашел это: https://github.com/jtilly/inih
Это только версия заголовка C++ inih.
inih (INI не изобретен здесь) - это простой синтаксический анализатор файлов .INI, написанный на C. Это всего лишь пара страниц кода, и он был разработан, чтобы быть небольшим и простым, поэтому он хорош для встраиваемых систем. Он также более или менее совместим со стилями .INI файлов в стиле Python ConfigParser, включая многострочный синтаксис в стиле RFC 822 и записи name: value.