项目优化中ini配置文件解析器

目录

一、项目背景

二、ini配置文件

2.1 ini文件格式

2.2 ini文件解析器代码

三、注册表的读写

3.1 项目背景

3.2 QSetting读写ini文件

 3.3 QSetting读写注册表


一、项目背景

        在停车管理项目中不同道闸口的终端配置可能不同,如靠近居民楼的道闸终端LED的语音播报音量和靠近马路的道闸门口不同;不同终端道闸锁闸时间也可能不同,诸如此类放在数据库中,不同的终端在启动时必须先连接到数据库才能加载,远没有本地配置文件方便,也不如配置文件方便技术支持修改方便,对于此类本地化配置的参数需要进行提取改写到本地配置文件中。

二、ini配置文件

2.1 ini文件格式

        ini文件简单,方便书写,但是只能表示二维数据结构;但相较于xml和json修改方便,也不容易修改出错,更适合做配置文件;xml和json在复杂的数据传输中更为合适。

2.2 ini文件解析器代码

    这里以map作为内存缓存进行配置文件的读写,配置文件中的不同值需要以重载如下。

#pragma once
#include<string>
#include<map>
class Value
{
public:
	Value() = default;
    //重载不同类型的构造函数
	Value(bool);
	Value(int);
	Value(double);
	Value(std::string&);
	Value(const char*);
	//操作符重载 支持不同的类型直接=赋值给value
	Value& operator=(bool);
	Value& operator=(int);
	Value& operator=(double);
	Value& operator=(std::string&);
	Value& operator=(const char*);

    //重载不同类型 便于Value直接赋值转换给不同类型值
	//类型转换没有返回值 因为返回值必为该类型
	operator bool();
	operator int();
	operator double();
	operator std::string();
private:
	std::string m_value;
};

using Section = std::map<std::string, Value>;

class iniFile
{
    public:
		iniFile() = default;
		bool load(const std::string&filename);
		Value &getValue(const std::string&section, const::std::string&key);
		Section &operator[](const std::string&section);
		void SetValue(const std::string&section, const::std::string&key,const Value&value);
		bool hasKey(const std::string&section, const::std::string&key);
		bool hasSection(const std::string&section);
		void remove(const std::string&section, const::std::string&key);
		void remove(const std::string&section);
		std::string str();
		bool save(const std::string& name);
		void clear();
		
    private:
		std::string trim(std::string s);
	private:
		std::map<std::string, Section>m_mapSection;
	  
};

解析器实现代码 

#include "iniFile.h"
#include<sstream>
#include<fstream>

#define ConvertValue(value,m_value)\
	std::stringstream ss;\
	ss<<value;\
	ss>>m_value;

Value::Value(bool value)
{
	m_value = value ? "true":"false"; 
}

Value::Value(int value)
{
	*this = value;
}
Value::Value(double value)
{
	*this = value;
}
Value::Value(std::string&value)
{
	*this = value;
}
Value::Value(const char*value)
{
	*this = value;
}


Value& Value::operator=(bool value)
{
	m_value = value ? "true" : "false";
	return *this;
}
Value& Value::operator=(int value)
{
	std::stringstream ss;
	ss << value;
	ss >> m_value;
	return *this;
}
Value& Value::operator=(double value)
{
	std::stringstream ss;
	ss << value;
	ss >> m_value;
	return *this;
}
Value& Value::operator=(std::string&value)
{
	m_value = value;
	return *this;
}
Value& Value::operator=(const char*value)
{
	m_value = value;
	return *this;
}

//类型重载 当Value赋值给对应类型时默认调用该重载eg bool b = value;
Value::operator bool()
{
	return m_value == "true";
}

Value::operator int()
{
	return std::atoi(m_value.c_str());
}
Value::operator double()
{
	return std::atof(m_value.c_str());
}
Value::operator std::string()
{
	return m_value;
}


//ini文件操作
std::string iniFile::trim(std::string s)
{
	if (s.empty())
	{
		return s;
	}
	s.erase(0, s.find_first_not_of(" \n\r"));
	s.erase(s.find_last_not_of(" \n\r")+1);
	return s;
}
bool iniFile::load(const std::string&filename)
{
	if (filename.empty())
	{
		return false;
	}
	std::ifstream fin(filename);//filename 按行读取文件
	if (fin.fail())
	{
		return false;
	}
	std::string line, section;
	while (std::getline(fin, line))
	{
		line = trim(line);
		if (line == "")
		{
			continue;
		}
		
		if (line.at(0) == '[')
		{
			int pos = line.find_first_of(']');
			section = trim(line.substr(1, pos - 1));
			m_mapSection[section] = Section();
		}
		else
		{
			int pos = line.find_first_of('=');
			std::string key = trim(line.substr(0, pos));
			std::string value = trim(line.substr(pos + 1, line.size() - pos));
			m_mapSection[section].insert(std::pair<std::string,std::string>(key, value));
		}
	}
	fin.close();
	return true;

}

Value & iniFile::getValue(const std::string&section, const::std::string&key)
{
	return m_mapSection[section][key];
}
Section & iniFile::operator[](const std::string&section)
{
	return m_mapSection[section];
}

void iniFile::SetValue(const std::string&section, const::std::string&key,const Value&value)
{
	m_mapSection[section][key] = value;
}
bool iniFile::hasKey(const std::string&section, const::std::string&key)
{
	return hasSection(section) ? (m_mapSection[section].count(key)>0 ? true : false) : false;
}
bool iniFile::hasSection(const std::string&section)
{
	return m_mapSection.count(section) > 0 ? true : false;
}

void iniFile::remove(const std::string&section, const::std::string&key)
{
	if (hasKey(section, key))
	{
		m_mapSection[section].erase(key);
	}
}
void iniFile::remove(const std::string&section)
{
	if (hasSection(section))
	{
		m_mapSection.erase(section);
	}
}
void iniFile::clear()
{
	m_mapSection.clear();
}

std::string iniFile::str()
{
	std::stringstream ss;
	for (auto it = m_mapSection.begin(); it != m_mapSection.end();++it)
	{
		ss << "[" << it->first << "]" << std::endl;
		for (auto iter = it->second.begin(); iter != it->second.end(); ++iter)
		{
			ss << iter->first << " = " <<std::string(iter->second)<< std::endl;
		}
		ss << std::endl;
	}
	return ss.str();
}

bool iniFile::save(const std::string& name)
{
	std::ofstream fout(name);
	if (fout.fail())
	{
		return false;
	}
	fout << str();
	fout.close();
	return true;
}

 测试代码

#include<iostream>
#include"iniFile.h"
using namespace std;

int main()
{
	iniFile CfgFile;
	CfgFile.load("./Config.ini");
	std::string ip = CfgFile.getValue("Server", "ip");
	int port = CfgFile["Server"]["port"];
	CfgFile.SetValue("Server", "hostName", "wch");
	CfgFile.SetValue("User", "vipUser", "wch");
	CfgFile.SetValue("User", "CommonUser", "zhangsan");
	bool bC = CfgFile.hasKey("User", "CommonUser");
	CfgFile.remove("User", "CommonUser");
	bool  bS = CfgFile.save("./modify.ini");
	return 0;
}

三、注册表的读写

3.1 项目背景

        一般软件授权信息采用硬件加密好一点,但某些项目可能由于一些原因必须临时软授权供临时使用或体验,这种授权信息一般为加密信息,写在ini配置文件中,容易被无意间修改而导致软件解析授权信息失败从而无法使用,因此一般写在系统注册表中较好,不容易被修改。

3.2 QSetting读写ini文件

头文件



#pragma once
#include <QSettings>
#include <QMap>
#include <QVariant>
#include <QMutex>
#include <string>
#include <vector>
using std::wstring;
using std::vector;


class ConfigUtil
{
public:
	ConfigUtil(void);///<构造函数
	~ConfigUtil(void);///<析构函数

	ConfigUtil(ConfigUtil &&);   //启用默认的移动构造函数
	ConfigUtil& operator = (ConfigUtil&&);

	ConfigUtil& operator = (const ConfigUtil& h) = delete;
	ConfigUtil(const ConfigUtil& h) = delete;

	static ConfigUtil *pmsIniInstance();

	int openFile(const QString& file, QSettings::Format format);
	int closeFile();
	int sync();


	QVariant getDefault(const QString& path);
	int setDefault(const QString& path, const QVariant& v);

	QVariant get(const QString& path, bool useDefault = true);
	int set(const QString& path, const QVariant& v);

	int writeDefaultToSetting();
	

private:
	QSettings* _setting = nullptr;
	QMap<QString, QVariant> _defaultSetting;
	QMutex _mutex;

};

cpp实现文件

#include "QSettingsTest.h"
#include <QMutexLocker>

Q_GLOBAL_STATIC(ConfigUtil, configUtil)

ConfigUtil::ConfigUtil() :_mutex(QMutex::Recursive)
{

}

ConfigUtil* ConfigUtil::pmsIniInstance()
{
	return configUtil();
}

ConfigUtil::~ConfigUtil()
{
	closeFile();
}

ConfigUtil::ConfigUtil(ConfigUtil && other)
{
	*this = std::move(other);
}

ConfigUtil& ConfigUtil::operator = (ConfigUtil&& other)
{
	if (this == &other)
	{
		return *this;
	}

	QMutexLocker locker(&this->_mutex);
	QMutexLocker locker2(&other._mutex);

	this->_setting = other._setting;
	other._setting = nullptr;

	this->_defaultSetting = std::move(other._defaultSetting);
	return *this;
}

int ConfigUtil::openFile(const QString& file, QSettings::Format format)
{
	QMutexLocker locker(&_mutex);
	QSettings* setting = new(std::nothrow) QSettings(file, format);
	if (setting)
	{
		setting->setIniCodec("UTF-8");
		closeFile();
		_setting = setting;
		_defaultSetting.clear();
		return 0;
	}
	return -1;
}

int ConfigUtil::closeFile()
{
	QMutexLocker locker(&_mutex);
	if (_setting)
	{
		delete _setting;
		_setting = nullptr;
		_defaultSetting.clear();
	}

	return 0;
}

int ConfigUtil::sync()
{
	QMutexLocker locker(&_mutex);
	if (_setting)
	{
		_setting->sync();
		return (_setting->status() != QSettings::AccessError) ? 0 : -1;
	}
	return -1;
}

QVariant ConfigUtil::getDefault(const QString& path)
{
	QMutexLocker locker(&_mutex);

	auto it = _defaultSetting.find(path);
	if (it == _defaultSetting.end())
	{
		QVariant var;
		return var;
	}
	return it.value();
}

int ConfigUtil::setDefault(const QString& path, const QVariant& v)
{
	QMutexLocker locker(&_mutex);
	_defaultSetting[path] = v;
	return 0;
}

QVariant ConfigUtil::get(const QString& path, bool useDefault)
{
	QMutexLocker locker(&_mutex);
	if (!_setting)
	{
		return -1;
	}
	if (useDefault)
	{
		return _setting->value(path, _defaultSetting[path]);
		//Returns the value for setting key. If the setting doesn't exist, returns defaultValue.
	}
	else
	{
		return _setting->value(path);
		//If no default value is specified, a default QVariant is returned.
	}
}

int ConfigUtil::set(const QString& path, const QVariant& v)
{
	QMutexLocker locker(&_mutex);
	if (!_setting)
	{
		return -1;
	}
	_setting->setValue(path, v);
	return 0;
}

int ConfigUtil::writeDefaultToSetting()
{
	QMutexLocker locker(&_mutex);
	if (!_setting)
	{
		return -1;
	}

	auto it = _defaultSetting.begin();
	auto list = _setting->allKeys();
	for (it; it != _defaultSetting.end(); it++)
	{
		if (!list.contains(it.key()))
		{
			if (it.value().isValid() && (!it.value().isNull()))
			{
				_setting->setValue(it.key(), it.value());
			}
		}
	}
	return 0;
}







 3.3 QSetting读写注册表

注册表读写参考之前博客:

项目优化之开机自启动-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值