Creating a simple configuration file and parser in C++

前端 未结 12 710
谎友^
谎友^ 2020-12-07 10:55

I am trying to create a simple configuration file that looks like this

url = http://mysite.com
file = main.exe
true = 0

when the program ru

相关标签:
12条回答
  • 2020-12-07 11:35

    I've searched config parsing libraries for my project recently and found these libraries:

    • http://www.hyperrealm.com/libconfig/ - small but powerfull and easy-to-use library, examples of using are in the source package and here
    • http://pocoproject.org/docs/Poco.Util.PropertyFileConfiguration.html - a part of pocoproject. You can use abstraction in your code and behind that use various supported implementations (ini files, Xml configs, even environment variables)
    0 讨论(0)
  • 2020-12-07 11:37

    A naive approach could look like this:

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

    Now you can access each option value from the global options map anywhere in your program. If you want castability, you could make the mapped type a boost::variant.

    0 讨论(0)
  • 2020-12-07 11:39

    Why not trying something simple and human-readable, like JSON (or XML) ?

    There are many pre-made open-source implementations of JSON (or XML) for C++ - I would use one of them.

    And if you want something more "binary" - try BJSON or BSON :)

    0 讨论(0)
  • 2020-12-07 11:40

    In general, it's easiest to parse such typical config files in two stages: first read the lines, and then parse those one by one.
    In C++, lines can be read from a stream using std::getline(). While by default it will read up to the next '\n' (which it will consume, but not return), you can pass it some other delimiter, too, which makes it a good candidate for reading up-to-some-char, like = in your example.

    For simplicity, the following presumes that the = are not surrounded by whitespace. If you want to allow whitespaces at these positions, you will have to strategically place is >> std::ws before reading the value and remove trailing whitespaces from the keys. However, IMO the little added flexibility in the syntax is not worth the hassle for a config file reader.

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

    (Adding error handling is left as an exercise to the reader.)

    0 讨论(0)
  • 2020-12-07 11:41

    libconfig is very easy, and what's better, it uses a pseudo json notation for better readability.

    Easy to install on Ubuntu: sudo apt-get install libconfig++8-dev

    and link: -lconfig++

    0 讨论(0)
  • 2020-12-07 11:41

    SimpleConfigFile is a library that does exactly what you require and it is very simple to use.

    # File file.cfg
    url = http://example.com
    file = main.exe
    true = 0 
    

    The following program reads the previous configuration file:

    #include<iostream>
    #include<string>
    #include<vector>
    #include "config_file.h"
    
    int main(void)
    {
        // Variables that we want to read from the config file
        std::string url, file;
        bool true_false;
    
        // Names for the variables in the config file. They can be different from the actual variable names.
        std::vector<std::string> ln = {"url","file","true"};
    
        // Open the config file for reading
        std::ifstream f_in("file.cfg");
    
        CFG::ReadFile(f_in, ln, url, file, true_false);
        f_in.close();
    
        std::cout << "url: " << url << std::endl;
        std::cout << "file: " << file << std::endl;
        std::cout << "true: " << true_false << std::endl;
    
        return 0;
    }
    

    The function CFG::ReadFile uses variadic templates. This way, you can pass the variables you want to read and the corresponding type is used for reading the data in the appropriate way.

    0 讨论(0)
提交回复
热议问题