c++读取conf文件

c++格式化读取conf

conf文件的结构

[OUTPUT]
OutputPath = ./output
HpackDecompress = false

1.思考选用什么数据结构(容器选型)

​ 第一阶段:我想的是直接用string,所有操作对string

​ 第二阶段:使用map

​ 第三阶段:使用multimap 因为key存在重复

2.预先处理文件,让存储更加方便

初始化文件,要解决两个问题:1.删除注释行,即#行 2. 删除空行

参考代码:

​ 去掉空行(链接忘了)

#include<iostream>
#include<fstream>
#include<regex>
#include<string>
#include<cstdlib>
#include<deque>
using namespace std;
/*
*删除文本文件的空行
*
*/
int rm_BlankLine(string file){//定义了一个函数,输入的string变量是文件的地址
    fstream targetFile(file,fstream::in | fstream::out);//目标文件是这个文件的名字,这个是一个输出的文件类型的对象
    string line;//作为读取的每一行
    string temp;//作为缓存使用
    deque<string> noBlankLineQueue;//双向队列,只在队首和队尾操作时性能较好
        //判断文件是否打开
    if(!targetFile){
        cerr << "Can't Open File!" << endl;
        return EXIT_FAILURE;        
    }
    //记录文件开始位置
    auto StartPos = targetFile.tellp();
//循环读取判断文件的空行并放入队列
    while(getline(targetFile,line)){
        cout << targetFile.tellg() << endl;;    
        if(line.empty()){
            cout << "此行为空" << endl; 
        }else{
                cout << "上一行是空行" << endl;   
            noBlankLineQueue.push_back(line);
        }   
    }
    targetFile.close(); 
    //使用ofstream打开再关闭文件是为了清空源文件
    ofstream emptyFile(file);
    emptyFile.close();
    //重新打开文本文件
    fstream target(file,fstream::out | fstream::in);
    if(!target){
        cerr << "Can't Open File" << endl;
    }
    //获取队首和队尾
    auto begin = noBlankLineQueue.begin();
    auto end = noBlankLineQueue.end();
    //遍历双向队列中的元素
    //并写回文件
    while(begin != end){
        temp = *begin;
        cout << temp << endl;
        target << temp << endl; 
        ++begin;
    }
    target.close();
    return EXIT_SUCCESS;
}
int main(){
    rm_BlankLine("te.txt"); 
}

​ 去掉#行

#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int main() {
    ifstream file("test.txt");//打开文件
    string line;//定义一个string 的line
    int n, count = 0;//定义一个n,和count,初始化为0
    ofstream outfile("test2.txt", ios::out | ios::trunc);//定义输出的文件是保存在test2的文件夹
    cout << "Please input the line number you want to del:" << endl;//打印一段文字
    cin >> n;//输入n ,在这个文件中是要删除的行号
    while (!file.eof()) {//判断是否文本的最后一行
        getline(file, line);//将file的行写入string 类型line中
        /*
        在这个语句的时候,可以进行判断,把#开头的行也独立出来,把它删除,对于每一行都这样操作,那么就可以解决第一个#开头行的问题
        impl_1_1:不读取#开头的行
        在string中查找 # 字符
        如果找到了#字符,就不读取这一行
      
        	
        */
        if (count != n - 1)//如果要修改内容就在这修改line的内容,再存到文件中就行了
            /*
            在这个位置,在添加一个判断语句来判断是否要把这一行的数据存入新生成的文件中
            */
            outfile << line << endl;//把line的数据存入outfile的对象中
        count++;
    }
    outfile.close();//关闭输出文件对象
    file.close();//关闭输入文件对象
    //重新定义一个outfile1 和file1,用来保存输入文件的内容
    ofstream outfile1("test.txt", ios::out | ios::trunc);//将输出文件对象里面的内容保存诶test.txt的文件
    fstream file1("test2.txt");//将输入文件内容作为test2.txt
    while (!file1.eof()) {//如果file1没有到了最后一行
        getline(file1, line);//获取每一行的数据给line
        outfile1 << line << endl;//将输出行的内容给outfile1
    }
    outfile1.close();//关闭输出文件类型的outfile1
    file1.close();//关闭file1
    system("del test2.txt");//删除中间文件
    return 0;
}
————————————————
版权声明:本文为CSDN博主「业余选手李主任」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shujh_sysu/article/details/52072528

impl:

使用substr前,用find找到指定的下标

//检测#号
#include <iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
    string a = "ajf#kajfkajlfj";
    int pos;
    pos = a.find("#");
    std::cout << pos<<endl;
    getchar();
    return 0;
}

//删除#号行
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
int main() {
    ifstream file("**");//打开文件
    string line;//定义一个string 的line
    int count = 0;//定义一个n,和count,初始化为0
    //int n = 0;//删除某一行
    ofstream outfile("test2.conf", ios::out | ios::trunc);//定义输出的文件是保存在test2的文件夹
    cout << "Please input the line number you want to del:" << endl;//打印一段文字
    //cin >> n;//输入n ,在这个文件中是要删除的行号
    while (!file.eof()) {//判断是否文本的最后一行
        getline(file, line);//将file的行写入string 类型line中
        /*
        在这个语句的时候,可以进行判断,把#开头的行也独立出来,把它删除,对于每一行都这样操作,那么就可以解决第一个#开头行的问题
        impl_1_1:不读取#开头的行
        在string中查找 # 字符
        如果找到了#字符,就不读取这一行
        impl_1_2:不读取空行
        这个时候有一个疑问  ?  空行是不是  string = "\n"
        在这个基础上,我找到了另一段代码去验证,或者说是删除空行的方法

        */
        int pos;
        pos = line.find("#");
        if (pos)//如果要修改内容就在这修改line的内容,再存到文件中就行了
            /*
            在这个位置,在添加一个判断语句来判断是否要把这一行的数据存入新生成的文件中
            */
            outfile << line << endl;//把line的数据存入outfile的对象中
        count++;
    }
    outfile.close();//关闭输出文件对象
    file.close();//关闭输入文件对象
    //重新定义一个outfile1 和file1,用来保存输入文件的内容
    ofstream outfile1("***", ios::out | ios::trunc);//将输出文件对象里面的内容保存诶test.txt的文件
    fstream file1("test2.conf");//将输入文件内容作为test2.txt
    while (!file1.eof()) {//如果file1没有到了最后一行
        getline(file1, line);//获取每一行的数据给line
        outfile1 << line << endl;//将输出行的内容给outfile1
    }
    outfile1.close();//关闭输出文件类型的outfile1
    file1.close();//关闭file1
    system("del test2.conf");//删除中间文件
    return 0;
}
//删除空行,作者写得非常好,直接调用
#include<iostream>
#include<fstream>
#include<regex>
#include<string>
#include<cstdlib>
#include<deque>
using namespace std;
/*
*删除文本文件的空行
*
*/
int rm_BlankLine(string file) {//定义了一个函数,输入的string变量是文件的地址
    fstream targetFile(file, fstream::in | fstream::out);//目标文件是这个文件的名字,这个是一个输出的文件类型的对象
    string line;//作为读取的每一行
    string temp;//作为缓存使用
    deque<string> noBlankLineQueue;//双向队列,只在队首和队尾操作时性能较好
        //判断文件是否打开
    if (!targetFile) {
        cerr << "Can't Open File!" << endl;
        return EXIT_FAILURE;
    }
    //记录文件开始位置
    auto StartPos = targetFile.tellp();
    //循环读取判断文件的空行并放入队列
    while (getline(targetFile, line)) {
        cout << targetFile.tellg() << endl;;
        if (line.empty()) {
            cout << "此行为空" << endl;
        }
        else {
            cout << "上一行是空行" << endl;
            noBlankLineQueue.push_back(line);
        }
    }
    targetFile.close();
    //使用ofstream打开再关闭文件是为了清空源文件
    ofstream emptyFile(file);
    emptyFile.close();
    //重新打开文本文件
    fstream target(file, fstream::out | fstream::in);
    if (!target) {
        cerr << "Can't Open File" << endl;
    }
    //获取队首和队尾
    auto begin = noBlankLineQueue.begin();
    auto end = noBlankLineQueue.end();
    //遍历双向队列中的元素
    //并写回文件
    while (begin != end) {
        temp = *begin;
        cout << temp << endl;
        target << temp << endl;
        ++begin;
    }
    target.close();
    return EXIT_SUCCESS;
}
int main() {
    rm_BlankLine("***");
}

3.读取数据

读取数据要解决三个问题:

​ 1.读取[] 内的数据

​ 2.读取=号前的数据

​ 3.读取=号后的数据

impl

1.读取[]内的数据

实现方式,使用substring

substring(begin,end)

begin 使用find定位

//测试
#include<iostream>
#include<string>
using namespace std;
int main() {
  
	std::string a("[abc]");
	int begin, end;
	string temp;
	temp = a.substr(a.find("[")+1, a.find("]")-1);
	cout << temp << endl;
	getchar();
	return 0;

}
//out abc

2.读取=号前的数据

#include<iostream>
#include<string>
using namespace std;
int main() {
 
	std::string a("abc=bbcdjfkajf");
	int begin, end;
	string temp;
	temp = a.substr(0, a.find("="));
	cout << temp << endl;
	getchar();
	return 0;

}

3.读取=号后的数据

#include<iostream>
#include<string>
using namespace std;
int main() {
   
	std::string a("abc=bbcdjfkajf");
	int begin, end;
	string temp;
	temp = a.substr(a.find("=")+1, a.find("\n"));
	cout << temp << endl;
	getchar();
	return 0;

}
4.解决容器存储的问题

​ 1.存入所有的域,val用0来表示

#include <iostream>
#include<map>
using namespace std;
int main()
{
    
string str1 = "asbd";
string str2 = "asbaad";
map<string, string>a;
//使用insert函数插入数据

a.insert(pair<string,string>(str2, str1));
for (map<string, string>::iterator it = a.begin(); it != a.end(); it++)
{
    cout << it->first << ":" << it->second << endl;
}

getchar();
}

2.string判断代码

string::size_type idx,idx2;
        idx = line.find("[");//在a中查找b.
        idx2 = line.find("]");//在a中查找b.
if (idx == string::npos && idx2 == string::npos)//不存在。
        {
			continue;

        }
        else//存在。
        {
            string temp;
            temp = line.substr(line.find("[") + 1, line.find("]") - 1);
            cout << temp << endl;
            map1.insert(pair<string, string>(temp, "0"));
        }

3.如何实现两个multimap合并


#include <iostream>
#include<string>
#include<fstream>
#include <cstdlib>
#include<map>

using namespace std;
string getValue(string a, string b);
//int main()
//{
//    map<string,map<string, string>> map1;//后一次进行存储
//    map<string, string> map2;//第一存储
//    string FilePath = "";
//    ifstream file(FilePath);//相当于file.open 打开了文件
//    string line;//定义一个string 的line
//    int count = 0;//定义一个n,和count,初始化为0
//    while (!file.eof()) {//判断是否文本的最后一行
//        getline(file, line);//将file的行写入string 类型line中
//        /*
//        在这个语句的时候,可以进行判断,把#开头的行也独立出来,把它删除,对于每一行都这样操作,那么就可以解决第一个#开头行的问题
//        impl_1_1:不读取#开头的行
//        在string中查找 # 字符
//        如果找到了#字符,就不读取这一行
//        impl_1_2:不读取空行
//        这个时候有一个疑问  ?  空行是不是  string = "\n"
//        在这个基础上,我找到了另一段代码去验证,或者说是删除空行的方法
//
//        */
//        string::size_type idx,idx2;
//        idx = line.find("[");//在a中查找b.
//        idx2 = line.find("]");//在a中查找b.
//
//        if (idx == string::npos && idx2 == string::npos)//不存在。
//        {
//            string temp1, temp2;
//            temp2= line.substr(line.find("=") + 1, line.find("\n"));
//            temp1 = line.substr(0, line.find("="));//
//            map2.insert(pair<string, string>(temp1,temp2 ));
//
//        }
//        else//存在。
//        {
//            string temp, temp2;
//            temp = line.substr(line.find("[") + 1, line.find("]") - 1);
//            cout << temp << endl;
//            map1.insert(pair<string, string>(temp, "0"));
//        }
//        count++;
//    }
//
//    file.close();
//    for (map<string, string>::iterator it = map1.begin(); it != map1.end(); it++)
//    {
//        cout << it->first << ":" << it->second << endl;
//    }
//    for (map<string, string>::iterator it = map2.begin(); it != map2.end(); it++)
//    {
//        cout << it->first << ":" << it->second << endl;
//    }
//    getchar();
//    return 0;
//}   
multimap<string, string>map2;
multimap<string, multimap<string, string> >map1;
multimap<string, multimap<string, string> >::iterator p2;
multimap<string, string>::iterator p3;
int main()
{

    string flag;
    string FilePath = "***";
    ifstream file(FilePath);//相当于file.open 打开了文件
    string line;//定义一个string 的line
    int count = 0;//定义一个n,和count,初始化为0
    while (!file.eof()) {//判断是否文本的最后一行
        getline(file, line);//将file的行写入string 类型line中
        /*
        在这个语句的时候,可以进行判断,把#开头的行也独立出来,把它删除,对于每一行都这样操作,那么就可以解决第一个#开头行的问题
        impl_1_1:不读取#开头的行
        在string中查找 # 字符
        如果找到了#字符,就不读取这一行
        impl_1_2:不读取空行
        这个时候有一个疑问  ?  空行是不是  string = "\n"
        在这个基础上,我找到了另一段代码去验证,或者说是删除空行的方法

        */
        string::size_type idx, idx2;
        idx = line.find("[");//在a中查找b.
        idx2 = line.find("]");//在a中查找b.

        if (idx == string::npos && idx2 == string::npos)//不存在。
        {
            string temp1, temp2;
            temp2 = line.substr(line.find("=") + 1, line.find("\n"));
            temp1 = line.substr(0, line.find("="));//
            map2.insert(pair<string, string>(temp1, temp2));
            map1.insert(make_pair(flag, map2));//flag是key不能重复

        }
        else//存在。
        {
            map2.clear();
            flag = line.substr(line.find("[") + 1, line.find("]") - 1);
        }
        count++;
    }

    file.close();
    //for (p2 = map1.begin(); p2 != map1.end(); p2++)
    //{
    //    for (p3 = p2->second.begin(); p3 != p2->second.end(); p3++)
    //    {
    //        cout << "[" << p2->first << "] " << endl;
    //        cout << p3->first << ":" << p3->second << endl;
    //    }
    //}
   string path;
   path = getValue("GLOBAL", "LogFile ");
   cout << path << endl;
   /*
   [GLOBAL]
LogFile = conf/log.conf
   
   */
    system("pause");
    return 0;

}

string getValue(string a, string b)
{
    string c;
    for (p2 = map1.begin(); p2 != map1.end(); p2++)
    {
        for (p3 = p2->second.begin(); p3 != p2->second.end(); p3++)
        {
            if (p2->first == a)
            {
                if (p3->first == b)
                {
                    c = p3->second;
                  
                    
                }
            }
        }
    }
    return c;
   
}

在这一部分遇到了一个问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LwORtaGs-1642649551783)(C:\Users\zhous\AppData\Roaming\Typora\typora-user-images\1642640847231.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GGIuPjA4-1642649551788)(C:\Users\zhous\AppData\Roaming\Typora\typora-user-images\1642640912548.png)]

c为空?发现logFile多了一个空格,把前面的改一改,再把后面的改一改,解决

5.将代码弄成一个类

第一次

具体文件代码如下

"FileReader.h"
#include<iostream>
#include<map>

class IniReader
{
public:
	IniReader();//构造函数
	~IniReader();//析构函数
	void Read(std::string s1);//读取路径
	std::string getValue(std::string a, std::string b);//输入前后输出

private:
	std::string filepath;//路径
	std::multimap<std::string, std::string>map2;//存入每一行
	std::multimap<std::string, std::multimap<std::string, std::string> >map1;//每一行存入对应的域
	std::multimap<std::string, std::multimap<std::string, std::string> >::iterator p2;
	std::multimap<std::string, std::string>::iterator p3;
};
"FileReader.cpp"
#include"FileReader.h"
#include <iostream>
#include<string>
#include<fstream>
#include <cstdlib>
#include<map>
using namespace std;
IniReader::IniReader()
{
	filepath = "";
}

IniReader::~IniReader()
{

}

void IniReader::Read(std::string s1)
{
	filepath = s1;
    string flag;
	ifstream file(filepath);
	string line;//定义一个string 的line
	int count = 0;//定义一个n,和count,初始化为0
	while (!file.eof()) {//判断是否文本的最后一行
		getline(file, line);//将file的行写入string 类型line中
        string::size_type idx, idx2;
        idx = line.find("[");//在a中查找b.
        idx2 = line.find("]");//在a中查找b.

        if (idx == string::npos && idx2 == string::npos)//不存在。
        {
            string temp1, temp2;
            temp2 = line.substr(line.find("=") + 1, line.find("\n"));
            temp1 = line.substr(0, line.find("=")-1);//
            map2.insert(pair<string, string>(temp1, temp2));
            map1.insert(make_pair(flag, map2));//flag是key不能重复

        }
        else//存在。
        {
            map2.clear();
            flag = line.substr(line.find("[") + 1, line.find("]") - 1);
        }
        count++;
    }
    file.close();
}

std::string IniReader::getValue(std::string a, std::string b)
{
    string c;
    for (p2 = map1.begin(); p2 != map1.end(); p2++)
    {
        for (p3 = p2->second.begin(); p3 != p2->second.end(); p3++)
        {
            if (p2->first == a)
            {
                if (p3->first == b)
                {
                    c = p3->second;


                }
            }
        }
    }
    return c;
}
main.cpp
#include <iostream>
#include "FileReader.h"
using namespace std;
int main() {
    IniReader reader;
    reader.Read("***");
    std::string path;
    path = reader.getValue("OUTPUT", "OutputPath");
    cout << path << endl; // 输出 ./ouput
    getchar();
}
总结

如果value里面有一个[或者],程序输出为空

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值