+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 92.51 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

Один из методов работы с конфигурационными файлами в С++ (Qt)

07.08.2012 12:19
unixod

Практически в каждом проекте, встает задача персистентного чтения/записи конфигурации. Не секрет что существует большое количество уже готовых библиотек для решения этой задачи. Некоторые из-них просты, некоторые чуть сложнее в использовании.
Если же проект разрабатывается с использованием Qt, думаю нет смысла линковать дополнительную библиотеку, так как в Qt есть все средства для создания очень простого, гибкого и кроссплатформенного решения.
Как раз о таком решении хочу расказать вам в этом посте.

Введение


В Qt есть очень удобный класс  QSettings . В принципе он очень прост в использовании:
/*
    main.cpp
*/
int main(int argc, char *argv[]){
    // эти настройки используются (неявно) классом QSettgins для
    // определения имени и местоположения конфига
    QCoreApplication::setOrganizationName("org");
    QCoreApplication::setApplicationName("app");
    ...
    return 0;
}

/*
    some.cpp
*/
void func(){
    QSettings conf;
    ...
    // запись в конфиг
    conf.setValue("section1/key1", someData);   // запись в секцию section1
    conf.setValue("key2", someData2);           // запись в секцию General
    ...
    // чтение из конфига
    QString strData = conf.value("section1/key1").toString();
}

Из приведенного выше примера, обычного использования  QSettings , сразу становятся видны проблемы расширяемости и поддержки кода:
  1. Если имена ключей прописывать явно в коде, то в дальнейшем мы можем столкнуться с ситуацией когда будет сложно удалять/добавлять новые ключи конфигурации. Т.е. при таком подходе, тут проблема в том что на этапе компиляции невозможно выловить инвалидные ключи.
  2. Чтобы избежать проблемы #1 мы могли бы выписать все ключи в отдельный заголовочный файл, и обращаться к ним через строковые константы. Для улучшения модульности кода и очистки глобальной области видимости, также стоило бы поместить все ключи в отдельное пространство имен.
    namespace Settings{
        const char * const key1 = "key1";
        const char * const section1_key1 = "section1/key1";
        const char * const section1_key2 = "section1/key2";
    }
    

    Но тут у нас появляется другая не очень приятная деталь:
    * во первых слишком многословно, т.е. информация дублируется (key1 -> "key1", и т.д.). В принципе это не удивительно, так как мы же как-то должны описать сериализацию имен ключей. Да мы могли бы написать макрос, но, по известным причинам, макросы стоит избегать, тем более если есть альтернативные варианты.
    * во вторых при достаточном количестве ключей и секций, велика вероятность, что придется прописывать константы для всех комбинаций, что не очень удобно. Конечно же мы можем завести константы для ключей и для секций отдельно, но тогда, при каждом обращении в  QSettings , придется производить объединение строк.

Если внимательно еще раз просмотреть все вышеописанные проблемы, то можно сделать вывод: ключ представлен строкой - это и есть основная проблема. Ведь действительно, если в качестве ключа мы будем использовать перечисления (enums), то все вышеперечисленное разом улетучивается.

Перечисления конечно же удобны, но  QSettings  требует, в качестве параметра ключа - строку. Т.е. нам нужен некоторый механизм, который давал бы нам возможность транслировать значения перечислений в строки (извлекать строковые значения элементов перечислений). Например из следующего перечисления:

enum Key{
    One,
    Two,
    Three
};

нужно как-то извлечь 3 строки: "One", "Two", "Three".
К сожалению стандартными средствами C++ это сделать невозможно. Но как же быть?
Тут нам на помощь приходит Qt со своей метаобъектной моделью, а если точнее  QMetaEnum . Про QMetaEnum  писать не буду, так как это уже отдельная тема. Могу лишь дать ссылки: раздва.

Реализация


Имея на вооружении  QMetaEnum , теперь мы можем реализовать класс Settings, лишенный всех вышеперечисленных недостатков, а также предоставляющий возможность задания дефолтных настроек. Класс Settings представляет из себя синглтон Мейерса, это нам дает простоту настройки и его использования:

settings.h (Раскрыть спойлер)

settings.cpp (Раскрыть спойлер)

В данной реализации, класс  QSettings , используется исключительно для кроссплатформенного доступа к настройкам. Конечно же по желанию  QSettgins  может быть заменен любым другим механизмом, например SQLite .

Пример использования


Класс Settings предоставляет очень простой и удобный интерфейс, состоящий всего из трех статических методов:
void setDefaults(const QString &str); - установка параметров поумолчанию
QVariant get(Key, Section); - чтение значения (секция может быть опущена)
ValueRef set(Key, Section); - запись значения (секция может быть опущена)

/*
    main.cpp
*/
#include <QtCore/QCoreApplication>
#include <QUrl>
#include <QFile>
#include "settings.h"

void doSome(){
    //чтение из секции General
    QString login = Settings::get(Settings::User).toString();    // login == "unixod"
    
    QUrl proxyUrl = Settings::get(Settings::URI, Settings::Proxy).toUrl();    // http://proxy_uri

    QString generalUrl = Settings::get(Settings::URI).toString();    // пусто
    if(generalUrl.isEmpty())
        Settings::set(Settings::URI) = "http://some_uri";
}

int main(int argc, char *argv[]){
    //данные параметры используются QSettings для определения куда сохранять конфигурацию
    QCoreApplication::setOrganizationName("unixod");
    QCoreApplication::setApplicationName("app");

    //по желанию можем установить дефолтную конфигурацию:
    QFile cfgDefaults(":/config/default.cfg");  // я обычно дефолтовые настройки помещаю в ресурсы
    cfgDefaults.open(QIODevice::ReadOnly);
    Settings::setDefaults(cfgDefaults.readAll());
    //...
    doSome();
    //...
    return 0;
}

вот пример синтаксиса описания настроек по умолчанию:

default.cfg (Раскрыть спойлер)

как можно заметить формат - простой:
[section name]/key : value;

Заключение


Стоит заметить что данный класс Settings легко расширяется. Т.е. при желании, добавить/удалить/переименовать какие-нибудь ключи или секции, всего лишь надо изменить соответствующий enum!

У читающего может возникнуть вопрос а нельзя ли как нибудь вынести общую логику "за скобки".
Ответ: можно но лучше не стоит. Так как метаобъектная модель Qt не работает с шаблонами, придется использовать макросы, что в свою очередь влечет за собой известные проблемы:

  • Сложность отладки
  • Затруднение анализа кода для IDE
  • Сложность восприятия, читающим, кода
  • и т.д.

При сборке не забываем включить поддержку С++11:
  • GCC:
    -std=с++0x
  • Qt project file:
    QMAKE_CXXFLAGS += -std=c++0x

Спасибо за внимание. )

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

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

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года