递归读取树状配置文件

配置文件内容:

root
{
  num{-1.2 32}
  human{man{boy},femal{girl}} #has other?
  #have many
  week{Sun. Mon. Tues. Wed. Thrus. Friday St.}
  "end of 'root'"{'are "you" sure'}
}

other{}

 

读取它类实现:


/************************************************************************/
只读不写,只支持字符串类型
类内部以树状存储配置项,空串被解释为指代根节点
支持配置项嵌套定义, 行注释
全局配置项err_code和err_text用于描述配置文件解析错误
空格解释为间隔符, 区分大小写
单双引号配对标识字符串
暂时不支持转义字符
不要求必须存在最末空行
将来要兼容常见书写格式
/************************************************************************/

// 应该先预读分析一遍,防止递归解析时陷入死循环??
// 而且将文件整体放入缓冲区更容易管理内存!!
// 但那样就不方便支持实现动态配置项了(就是违反只读不写原则)

class CCfgNode
{
public:
    CCfgNode()
    {
    };

    CCfgNode(string const &name)
    {
        this->name = name;
    };

    string name;
    vector<CCfgNode> value;
};

class CCfgFile 
{
public:
 CCfgFile();
 virtual ~CCfgFile();

    void setVal(string const &sID, string const &sVal, CCfgNode *pNode=NULL);  // 在指定节点下创建子孙节点
    void load(string const &sFn);
    void dump(FILE *pFile=NULL, CCfgNode *pNode=NULL, int level=0);

    char const *getVal(string const &sUP, string const &sID);
    int getVal(string const &sID, vector<char const *> &vSet);

private:
    void nest_parse(CCfgNode &node, string const &sEnder);  // 暂时仅支持花括号这样的简单的层次分界符
    CCfgNode *nest_scout(CCfgNode &node, string const &sID);

    CCfgNode root_;
    FILE *pfile_;  // 保存递归解析中的当前文件状态
};

 


//
// Construction/Destruction
//

CCfgFile::CCfgFile() : pfile_(NULL)
{

}

CCfgFile::~CCfgFile()
{

}


// 更新或增加配置项
inline void CCfgFile::setVal(string const &sID, string const &sVal, CCfgNode *pNode/*=NULL*/)
{
    if (pNode == NULL) pNode = &root_;
    int pos=0;
    for (pos=0; pos<pNode->value.size(); ++pos)
    {
        if (pNode->value[pos].name == sID) break;
    }
    if (pos == pNode->value.size())
    {
        pNode->value.push_back(CCfgNode(sID));
        pNode->value.back().value.push_back(CCfgNode(sVal));
    }
    else
    {
        pNode = &pNode->value[pos];
        for (pos=0; pos<pNode->value.size(); ++pos)
        {
            if (pNode->value[pos].name == sVal) break;
        }
        if (pos == pNode->value.size())
        {
            pNode->value.push_back(CCfgNode(sVal));
        }
        else
        {
            pNode->value[pos].name = sVal;
        }
    }
}


void CCfgFile::nest_parse(CCfgNode &node, string const &sEnder)
{
    string sName;
    int ch;
    do
    {
        ch = fgetc(pfile_);
        if (ch=='_' || ch=='.' || ch=='-' || isalnum(ch))  // 需要封装对标志符的识别
        {
            sName += ch;
        }
        else
        {
            if (!sName.empty())
            {
                node.value.push_back(CCfgNode(sName));
                sName.erase();
            }
            switch (ch)
            {
            case '}': return;
            case '{':
                {
                    if (node.value.empty())
                    {
                        setVal("err_code", "-2");
                        setVal("err_text", "lack of identifier before '{'");
                        return;
                    }
                    nest_parse(node.value.back(), "");
                    break;
                }
            case '#':
                {
                    do ch = fgetc(pfile_); while (ch!='/n' && ch!=EOF);
                    break;
                }
            case '`':
            case '/'':
            case '/"':
                {
                    char endofch = ch;
                    ch=getc(pfile_);
                    while (ch!=endofch && ch!=EOF)
                    {
                        if (ch=='/r' || ch=='/n')
                        {
                            setVal("err_code", "-3");
                            setVal("err_text", "string has been break");
                            return;
                        }
                        sName += ch;
                        ch=getc(pfile_);
                    }
                    node.value.push_back(CCfgNode(sName));
                    sName.erase();
                    break;
                }
            default: break;
            }
        }
    }
    while (ch != EOF);
}


void CCfgFile::load(string const &sFn)
{
    pfile_ = fopen(sFn.c_str(), "rb");
    if (pfile_ == NULL)
    {
        setVal("err_code", "-1");
        setVal("err_text", "open file fail");
        return;
    }

    vector<CCfgNode>().swap(root_.value);  // 彻底清空根节点
    nest_parse(root_, "");
    fclose(pfile_);
    pfile_ = NULL;
}


void CCfgFile::dump(FILE *pFile/*=NULL*/, CCfgNode *pNode/*=NULL*/, int level/*=0*/)
{
    if (pNode == NULL) pNode = &root_;
    if (pFile == NULL) pFile = stderr;
    for (int i=0; i<pNode->value.size(); ++i)
    {
        fprintf(pFile, "%*s%s/n", level*4, " ", pNode->value[i].name.c_str());
        dump(pFile, &pNode->value[i], level+1);
    }
}


CCfgNode *CCfgFile::nest_scout(CCfgNode &node, string const &sID)
{
    if (node.name == sID) return &node;
    CCfgNode *pNode=NULL;
    for (int i=0; i<node.value.size(); ++i)
    {
        pNode = nest_scout(node.value[i], sID);
        if (pNode != NULL) break;
    }
    return pNode;
}


char const *CCfgFile::getVal(string const &sUP, string const &sID)
{
    CCfgNode *pNode=nest_scout(root_, sUP);
    if (pNode != NULL)
    {
        for (int i=0; i<pNode->value.size(); ++i)
        {
            if (pNode->value[i].name == sID)
            {
                pNode = &pNode->value[i];
                if (!pNode->value.empty())
                {
                    return pNode->value[0].name.c_str();  // 只取首条配置子项的值
                }
            }
        }
    }
    return "";  // 如此返回值到上层调用就不能区分配置项空值与不存在这两种情形了
}


int CCfgFile::getVal(string const &sID, vector<char const *> &vSet)
{
    CCfgNode *pNode=nest_scout(root_, sID);
    if (pNode != NULL)
    {
        for (int i=0; i<pNode->value.size(); ++i)
        {
            vSet.push_back(pNode->value[i].name.c_str());
        }
    }
    return pNode!=NULL ? pNode->value.size() : 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 在读取YML配置文件的过程中,可以通过key来获取特定配置项的值。在Java中,可以使用YAML库来解析YML文件。 首先,需要引入相应的依赖,例如SnakeYAML库。接着,可以使用YAML库提供的方法加载YML文件。 ```java import org.yaml.snakeyaml.Yaml; public class YmlReader { public static void main(String[] args) { Yaml yaml = new Yaml(); try (InputStream inputStream = YmlReader.class .getClassLoader() .getResourceAsStream("config.yml")) { // 加载YML文件并解析为Map结构 Map<String, Object> yamlConfig = yaml.load(inputStream); // 通过key获取特定配置项的值 String value = (String) yamlConfig.get("key"); System.out.println("配置项的值为: " + value); } catch (IOException e) { e.printStackTrace(); } } } ``` 上述代码中,假设YML文件名为config.yml,并放置在resources目录下。通过getClassLoader().getResourceAsStream("config.yml")方法来获取YML文件的输入流。然后,使用YAML库的load方法将YML文件解析为Map结构。接着,可以通过指定key来获取相应的值,注意要进行类型转换。 总之,通过以上的代码,我们可以通过key来读取YML配置文件,获取所需的配置项的值。 ### 回答2: 通过key读取yml配置文件可以使用Java中的Yaml库来实现。首先,我们需要引入合适的依赖项,例如SnakeYAML。 然后,我们可以使用下面的代码片段来实现通过key读取yml配置文件的功能: ```java import org.yaml.snakeyaml.Yaml; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.Map; public class YmlReader { public static void main(String[] args) { // 指定yml配置文件路径 String filePath = "config.yml"; // 指定要读取的key String key = "exampleKey"; try { // 创建Yaml对象 Yaml yaml = new Yaml(); // 将yml文件加载为Map实例 Map<String, Object> data = yaml.load(new FileInputStream(filePath)); // 根据key获取配置值 Object value = getValueByKey(data, key); // 输出配置值 System.out.println("配置值:" + value); } catch (FileNotFoundException e) { e.printStackTrace(); } } // 递归获取配置值 private static Object getValueByKey(Map<String, Object> map, String key) { for (Map.Entry<String, Object> entry : map.entrySet()) { String k = entry.getKey(); Object v = entry.getValue(); if (k.equals(key)) { return v; } else if (v instanceof Map) { Object value = getValueByKey((Map<String, Object>) v, key); if (value != null) { return value; } } } return null; } } ``` 在上述代码中,我们首先创建了一个Yaml对象,并使用该对象的`load`方法将yml文件加载为一个Map实例。然后,通过`getValueByKey`方法递归地遍历Map实例,寻找指定的key对应的值。 最后,我们可以根据具体的需求对获取到的配置值进行操作,例如在控制台输出配置值。 ### 回答3: 在Python中,通过key读取.yml配置文件可以使用PyYAML库来实现。首先,我们需要安装PyYAML库,可以使用pip命令进行安装。 安装完PyYAML库后,我们可以使用以下代码来读取.yml配置文件中的内容: ```python import yaml # 读取配置文件 with open('config.yml', 'r') as f: config = yaml.safe_load(f) # 通过key读取配置项的值 value = config['key'] print(value) ``` 以上代码首先使用`open()`函数打开.yml配置文件,并指定为只读模式。然后,使用`yaml.safe_load()`函数将配置文件的内容加载为Python的字典对象。接下来,我们可以通过key来获取配置项的值,将其赋给变量`value`。最后,通过`print()`函数将获取到的值打印出来。 需要注意的是,上述代码中的`config.yml`为.yml配置文件的路径,需要根据实际情况进行修改。 另外,如果配置文件中有多层级的结构,我们可以通过多个key来逐级获取值。例如,配置文件内容如下: ```yaml key1: key2: key3: value ``` 我们可以使用以下代码来获取`key3`的值: ```python value = config['key1']['key2']['key3'] ``` 以上就是通过key读取.yml配置文件的方法。希望对你有帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值