Професионална програма
Loading...
Smeshan avatar Smeshan 89 Точки

Четене на настройки от файл

Здравейте,

искам да направя настройките да се четат от файл.

Това което направих за сега:

MonitorConfig.txt

name of the display:Hardwear renderering
display height:800
display width:600


EngineConfigLoader.cpp (не е целия)

const char* MONITOR_CFG_FILE = "../sdl_utils/config/MonitorConfig.txt";

static std::string readConfigFromFile(const int32_t lineNum) {
    std::fstream file(MONITOR_CFG_FILE );
    if (!file.is_open()) {
        std::cerr << "Unable to open config file: " << MONITOR_CFG_FILE << std::endl;
    }
    std::string configLine;
    int32_t currLine = 0;

    while (!file.eof()) { // eof -> end of file
        std::string discard;

        if (currLine == lineNum) {
            getline(file, discard, ':'); //delete text before ':'
            getline(file, configLine);
            //std::cerr << "Line: " << configLine << std::endl;
            break;
        }
        getline(file, discard);
        //std::cerr << "Discard: " << discard << std::endl;
        currLine++;
    }
    return configLine;
}

static void populateMonitorConfig(MonitorConfig &outConfig) {
    outConfig.windowName = readConfigFromFile(0);
    outConfig.windowHeight = stoi(readConfigFromFile(1));
    outConfig.windowWidth = stoi(readConfigFromFile(2));
    outConfig.windowFlags = WINDOW_SHOWN;
}

И няколко неща не ми харесват или се чудя как да станат:
1. Като станат 100 настройки, while цикъла ще има да си върти докато стигне до 87-мия ред (примерно) за да го вземе. :Х И т. н..
2. Реда на настройките във файла трябва напълно да отговаря на реда, в който съм ги написал в populateMonitorConfig() (или поне номера на реда да отговаря). Това ми се струва бомба със закъснител и отделно трудно за промени..
3. populateMonitorConfig() стана адски нечетима.. :/

Ще продължа да го мисля и преработвам, но ще се радвам да се получи някаква дискусия и да съберем добри идеи :)

Поздрави,
Илиян

Тагове:
1
C++ Applications Development 17/10/2021 00:07:01
Smeshan avatar Smeshan 89 Точки

Оправих точка 3 с един enum. По-добре стана.

enum monitorConfig {
    WINDOW_NAME,
    DISPLAY_HEIGHT,
    DISPLAY_WIDTH
};

...

static void populateMonitorConfig(MonitorConfig &outConfig) {
    outConfig.windowName = readConfigFromFile(WINDOW_NAME);
    outConfig.windowHeight = stoi(readConfigFromFile(DISPLAY_HEIGHT));
    outConfig.windowWidth = stoi(readConfigFromFile(DISPLAY_WIDTH));
    outConfig.windowFlags = WINDOW_SHOWN;
}

 

1
Smeshan avatar Smeshan 89 Точки

И още подобрения:

enum monitorConfig {
    WINDOW_NAME,
    DISPLAY_HEIGHT,
    DISPLAY_WIDTH
};

const char *MONITOR_CFG_FILE = "../sdl_utils/config/MonitorConfig.txt";

static std::vector<std::string> readConfigsFromFile() {
    std::vector<std::string> configs;
    std::fstream file(MONITOR_CFG_FILE);
    if (!file.is_open()) {
        std::cerr << "Unable to open config file: " << MONITOR_CFG_FILE << std::endl;
    }
    std::string configLine;
    std::string discard;

    while (!file.eof()) { // eof -> end of file
        getline(file, discard, ':'); //delete text before ':'
        getline(file, configLine);
        configs.push_back(configLine);
    }
    return configs;
}

static void populateMonitorConfig(MonitorConfig &outConfig) {
    std::vector<std::string> configs = readConfigsFromFile();

    outConfig.windowName = configs[WINDOW_NAME];
    outConfig.windowHeight = stoi(configs[DISPLAY_HEIGHT]);
    outConfig.windowWidth = stoi(configs[DISPLAY_WIDTH]);
    outConfig.windowFlags = WINDOW_SHOWN;
}

И все пак, това е един начин да се направи. А и станаха много include-и или това не е проблем?
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

0
17/10/2021 00:17:14
j.petrov_90 avatar j.petrov_90 370 Точки

Привет, Илиян,

Адмирации, че си правиш труда да работиш в тази посока!
За жалост, ако искаш функционалността да е четима, лесна за използване и трудна да правене на грешки - трябва да вложиш още усилия.

Главният проблем, е че във 1 файл се опитват да правиш 3 коренно различни неща:
- четене от файл следвайки някакъв стил (nameOfParam:value)
- валидация на прочетената ивформация
- попълване на информацията от файла в структурите на програмата ти.

Разбиий това в 3 отделни класа, които правят само по 1 нещо и си 6 :)
1) четене от файл - ще изчита информацията и ще я съхранява в удобна за ползване структура. Може да я сложиш в map/unordered_map, където за ключ имаш std::string (името на параметъра) и std::string за неговото value.
2) валидация на горната конфигурация - какво става ако ти попълня display width:pesho? std::stoi функцията в последствие би хвърлила exception
3) използваш новата си структура с валидирана информация да попълниш структурите от програмата си (това вече го имаш).
4) пиеш една бира за добре свършената работа

Поздрави
 

0
17/10/2021 00:21:02
Smeshan avatar Smeshan 89 Точки

Благодаря за насоките!

Ето каква я свърших:..
Създадох още файлове:
..
> sdl_utils
    > config
        > tools
            > ConfigApplier.h
            > ConfigExtractor.h
            > ConfigValidator.h
      > MonitorConfig.h
      > MonitorConfig.txt

 

MonitorConfig.txt

WINDOW_NAME:Hardwear renderering
DISPLAY_HEIGHT:800
DISPLAY_WIDTH:600

Сложих всички enum-и константи в MonitorConfig.h. Раздробих на класове. И вече EngineConfigLoader.cpp изглежда така:

. . .
/* C++ system icnludes */
#include <string>
#include <unordered_map>

/* Third-party icnludes */

/* Own icnludes */
#include "sdl_utils/config/tools/ConfigExtractor.h"
#include "sdl_utils/config/tools/ConfigApplier.h"

const char *MONITOR_CFG_FILE = "../sdl_utils/config/MonitorConfig.txt";

typedef std::unordered_map<std::string, std::string> configData;

static void populateMonitorConfig(MonitorConfig &outConfig) {
    const configData data = ConfigExtractor::readFromFile(MONITOR_CFG_FILE);
    ConfigApplier::setConfigs(data, outConfig);
}
. . .


По-добре е, ще видим като добавяме настройки дали ще сработва.
Мисля, че мястото на тези файлове не са в sdl_utils и май да изкарам папка tools отвън? Защото могат да се ползват и за други данни.

Поздрави!

П.С. Сега като го гледам втори път, не ми харесва в ConfigApplier.h да има windowName и т .н., неща които нямат общо с config applier. Може би не трябваше да го изкарвам от EngineConfigLoader.cpp, тоест да върна съдържанието на setConfigs() обратно както си беше. :?

1
17/10/2021 14:08:10
j.petrov_90 avatar j.petrov_90 370 Точки

Привет,

Започваш за си задаваш правилните въпроси. Това е хубаво.
"Туловете", които създаде нямат нищо общо с SDL.
Това са тулове за четене и валидиране на конфигурация. Тяхното място е ... в utils.

Грешно се мъчиш от "тула" да достъпъш логиката за съответния конфиг (например window name).
Тула трябва да е "глупав" и да не знае нищо за компонентите, които биха го използвали.
Той просто съхранява някакви стрингове.

Т.е. няма да имаш "ConfigApplier", а ще оставиш всеки, който го интересува да преизползва тоци тул и сам да си приложи логиката (да си сетне полетата).

Поздрави

0