C++实用工具类-ini配置文件解析

dcc084fe-a937-4cf6-9b2d-f59765a1db19

ini配置文件介绍

一种常见的kv结构的配置文件

主要格式为 key=value

同时支持section, kv归属于一个section 如:

[default]

key1=value1

key2=value2

[section2]

key1=value1

key2=value2

注释, 支持#作为注释开始标记, 本实现仅支持 #单独一行的情况

实现方式

解析文件后按照状态流转进行读取, 如下:

全部读取文件内容到内存后, 按照状态流转一次循环全部字符完成解析,解析内容存放成2级map结构

section-->IniSection

IniSection内部存放 key->value map

并对外提供查询value接口

 实现代码

代码目录:

IniConfig.h

#ifndef __INICONFIG_H__
#define __INICONFIG_H__

#include <string>
#include <map>
#include "IniSection.h"

class IniConfig
{
public:
    IniConfig();

    ~IniConfig();

    bool LoadFile(const std::string& iniFilePath);

    std::string GetValue(const std::string& secName, const std::string& key);

    int GetIntValue(const std::string& secName, const std::string& key);

private:
    std::map<std::string, IniSection> configMap_;
};

#endif

IniConfig.cpp

#include "IniConfig.h"
#include <fstream>
#include <string.h>
#include <memory>
using namespace std;

IniConfig::IniConfig()
{
}

IniConfig::~IniConfig()
{
}

enum class IniStat : int
{
    Start, //开始
    Section, //读取section部分
    Key, //读取key
    Value, //读取value
    Comment //注释
};

bool IniConfig::LoadFile(const string& iniFilePath)
{
    fstream fs;
    fs.open(iniFilePath, ios::in);
    if(!fs.is_open())
    {
        return false;
    }

    fs.seekg(0, ios::end);
    int length = fs.tellg();
    fs.seekg(0, ios::beg);

    char* buffer = new char[length+1];
    std::unique_ptr<char[]> bufferPtr(buffer);
    memset(buffer, 0, length+1);
    fs.read(buffer, length);
    
    IniStat stat = IniStat::Start;
    int pos = 0;
    string key;
    string value;
    IniSection iniSection;
    while(pos < length)
    {
        if(buffer[pos] == '[')
        {
            stat = IniStat::Section;
            configMap_.insert(make_pair(iniSection.sectionName_, iniSection));
            iniSection.Clear();
        }
        else if(stat == IniStat::Section)
        {
            if(buffer[pos] == ']')
            {
                stat = IniStat::Key;
            }
            else
            {
                iniSection.sectionName_ += buffer[pos];
            }
        }
        else if(buffer[pos] == '=')
        {
            stat = IniStat::Value;
        }
        else if(buffer[pos] == '\r' || buffer[pos] == '\n')
        {
            if(!key.empty())
            {
                iniSection.InsertItem(key, value);
                key.clear();
                value.clear();
            }
            stat = IniStat::Key;
        }
        else if(buffer[pos] == '#')
        {
            stat = IniStat::Comment;
        }
        else if(stat == IniStat::Key)
        {
            key += buffer[pos];
        }
        else if(stat == IniStat::Value)
        {
            value += buffer[pos];
        }
        pos++;
    }

    //最后没有换行的情况
    if(!key.empty())
    {
        iniSection.InsertItem(key, value);
    }

    if(!iniSection.Empty())
    {
        configMap_.insert(make_pair(iniSection.sectionName_, iniSection));
    }

    return true;
}

std::string IniConfig::GetValue(const std::string& secName, const std::string& key)
{
    auto itSection = configMap_.find(secName);
    if(itSection != configMap_.end())
    {
        return itSection->second.GetValue(key);
    }
    return "";
}

int IniConfig::GetIntValue(const std::string& secName, const std::string& key)
{
    string value = GetValue(secName, key);
    return atoi(value.c_str());
}

IniSection.h

#ifndef  __INISECTION_H__
#define __INISECTION_H__

#include <string>
#include <map>

class IniSection
{
public:
    IniSection();

    ~IniSection();

    bool Empty() const;

    void Clear();

    void InsertItem(const std::string& key, const std::string& value);

    std::string GetValue(const std::string& key);

    std::string sectionName_;
private:
    std::map<std::string, std::string> itemMap_;

};

#endif

IniSection.cpp

#include "IniSection.h"

IniSection::IniSection()
{  
}

IniSection::~IniSection()
{
}

void IniSection::Clear()
{
    sectionName_.clear();
    itemMap_.clear();
}

bool IniSection::Empty() const
{
    return sectionName_.empty();
}

void IniSection::InsertItem(const std::string& key, const std::string& value)
{
    itemMap_.insert(make_pair(key, value));
}

std::string IniSection::GetValue(const std::string& key)
{
    auto it = itemMap_.find(key);
    if(it != itemMap_.end())
    {
        return it->second;
    }
    return "";
}

测试代码:

#include "gtest.h"
#include "IniConfig.h"
#include <vector>
using namespace std;

class IniConfigTest : public ::testing::Test
{
};

TEST_F(IniConfigTest, TestSimple)
{
    IniConfig iniConfig;
    if(!iniConfig.LoadFile("./src/unittest/test.ini"))
    {
        GTEST_FAIL();
        return;
    }

    EXPECT_TRUE(iniConfig.GetValue("default","app_name") == "IniConfigTest");
    cout << "default.app_name=" << iniConfig.GetValue("default","app_name") << endl;

    EXPECT_TRUE(iniConfig.GetValue("default","testkey3") == "testvalue3");
    cout << "default.testkey3=" << iniConfig.GetValue("default","testkey3") << endl;
    
    EXPECT_TRUE(iniConfig.GetIntValue("default","testkey4") == 200);

    string section1_app_name = iniConfig.GetValue("section1","app_name");
    cout << "section1.app_name=" << section1_app_name << endl;
    EXPECT_TRUE(section1_app_name == "section1_IniConfigTest");
}

测试用ini文件

[default]
#test comment
app_name=IniConfigTest
testkey1=testvalue1
#test comment
testkey2=testvalue2
#test comment
testkey3=testvalue3
testkey4=200

[section1]
app_name=section1_IniConfigTest
testkey1=section1_testvalue1
testkey2=section1_testvalue2
testkey3=section1_testvalue3
testkey4=section1_200

运行效果:

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: INIInitial Input)配置文件是一种常用的配置文件格式,用于存储和读取程序的配置信息。以下是读写INI配置文件的步骤: 1. 读取INI配置文件:首先,我们需要打开INI配置文件,并逐行读取文件内容。可以使用适当的函数或库来实现文件读取操作。在读取过程中,我们需要解析每一行内容,并提取所需的配置信息。 2. 解析INI配置文件:在解析每一行配置信息之前,我们还需要进行一些校验和处理。首先,我们需要忽略注释行(行首以分号 “;” 或井号 “#” 开头的行),然后我们需要忽略空行。接下来,我们可以使用适当的函数或算法来解析每一行的配置信息。一般来说,每一行配置信息的格式为“键=值”的形式,我们需要提取出键和对应的值。 3. 存储INI配置文件:如果需要修改INI配置文件或添加新的配置项,我们需要打开INI配置文件,并写入新的配置信息。首先,我们需要读取原有的配置信息,并将其保存到内存中。然后,我们可以使用合适的函数或库来修改配置信息或添加新的配置项。最后,我们将修改后的配置信息写入INI配置文件。 4. 错误处理:在读写INI配置文件的过程中,如果遇到错误,例如文件不存在、文件权限不足、文件格式错误等,我们需要进行适当的错误处理。可以根据实际情况输出错误信息或进行其他操作。 总结:读写INI配置文件是一种常见的配置文件操作方法,需要按照一定的步骤进行。通过逐行读取和解析配置文件内容,可以实现读取INI配置文件的功能。通过修改和添加配置信息,并将其写入配置文件,可以实现存储INI配置文件的功能。在进行读写操作时,还需要注意错误处理,以保证程序的稳定性和可靠性。 ### 回答2: INI配置文件是一种常见的配置文件格式,用于存储程序的配置信息。C语言提供了一些函数库用于读写INI文件,包括<Windows.h>头文件中的GetPrivateProfileString、GetPrivateProfileInt、WritePrivateProfileString等函数。 首先,要读取INI配置文件中的值,可以使用GetPrivateProfileString函数。该函数的参数包括INI文件的路径、节名和键名,同时可以传入一个缓冲区,函数将根据配置文件中的键值将对应的值复制到缓冲区中。 另外,如果配置文件中的值是整数类型的,可以使用GetPrivateProfileInt函数,该函数会直接返回键值对应的整数值。 如果需要写入INI配置文件,可以使用WritePrivateProfileString函数。该函数的参数包括INI文件的路径、节名、键名和值。调用该函数后,程序会将键值对按照指定的格式写入配置文件中。 在使用这些函数前,需要先加载Windows.h头文件。同时,在使用INI配置文件时,需要注意配置文件的路径是否正确,以及节名和键名是否正确。读取INI文件时,还要判断读取的值是否为空,以避免出现错误。 总结起来,C语言提供了一些函数用于读写INI配置文件,这些函数可以方便地读取和写入配置信息。通过合理的使用这些函数,可以更好地管理程序的配置,提升程序的可配置性和可维护性。 ### 回答3: INIInitialization)是一种常见的配置文件格式,用于存储应用程序的设置和参数。在C语言中,可以通过读写INI配置文件来实现配置文件的加载和保存。 在读取INI配置文件时,可以使用标准库函数fopen()来打开文件,然后通过fgets()函数逐行读取文件内容。读取到的每一行都可以通过字符串处理函数来分割成键值对。常用的字符串处理函数包括strtok()、strstr()和sscanf()等。使用时需要根据INI配置文件的具体格式和规范来进行相应的处理。 在写入INI配置文件时,可以使用标准库函数fopen()来创建或打开文件,然后使用fprintf()函数来向文件写入内容。需要注意的是,写入INI配置文件时需要按照一定的格式和规范来进行写入,以保证配置文件的正确性和可读性。 读写INI配置文件的步骤主要包括以下几个方面: 1. 打开INI配置文件:使用fopen()函数打开INI配置文件。 2. 读取INI配置文件内容:使用fgets()函数逐行读取配置文件内容,并使用字符串处理函数处理每一行的内容。 3. 解析INI配置文件内容:根据INI配置文件的格式和规范,将每一行的内容解析成键值对,并存储到相应的数据结构中。 4. 关闭INI配置文件:使用fclose()函数关闭INI配置文件,释放资源。 5. 根据需要进行数据操作:根据存储的键值对,进行相应的数据操作,如设置应用程序的参数、初始化等。 6. 写入INI配置文件:使用fprintf()函数向INI配置文件写入数据,按照INI配置文件的格式和规范进行写入。 总结:通过使用C语言提供的标准库函数,可以实现INI配置文件的读取和写入。读取时需要逐行读取并解析每一行的内容,写入时需要按照INI配置文件的格式进行写入。读写INI配置文件是一种常见的配置文件处理方式,具有简单、灵活的优点,适用于各种应用程序的配置管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值