文件操作之配置文件

一、前言

我比较喜欢用ini后缀文件作为配置文件,因为它存储的数据结构看上起很清晰+数据读写很方便。

//ini数据存储结构
[section]
key=value

二、使用的函数

#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")	//不要忘了加载库

//读取字符串的项
GetPrivateProfileString(section, key, defineValue, outValue, outValueLen, filePath);

//读取整数的项
GetPrivateProfileInt(section, key, defineValue, filePath);

//只能以字符串方式写入,若要写入整数得转绕下弯,手动转成字符串。
WritePrivateProfileString(section, key, value, filePath);

三、应用

1、提前准备: 创建ini文件+手写内容
吐槽:程序中没必要考虑文件没创建情况!!!软件发布时,配置文件是一起打包的。若程序代码中发现找不到配置文件,果断exit(0)吧。顺便在弹个提示框,“找不到配置文件xxx.ini,请确认你使用的是正版软件”。

2、撸代码
考虑到有多个配置文件,我写的这个类必须可以复用。面对不同的配置文件,差异之处在于文件名不同+一套{section+key}不同,而读取、设置数据方式都是相同的。于是,有了下边这样奇葩的设计。

2.1、类名

	class FileIni

这是个基类!!!可以派生出"张三Ini",“李四Ini”。

2.2、成员函数

public:
	//读取,让调用者知道是否成功。
	bool read();

	//设置本地+文件,考虑到配置文件很少写入,在这里顺便更新了文件数据
	void set(string key, string value);
	void set(string key, int value);

	//返回的都是引用,因为数据都会存在成员变量中
	const string& getString(string key);
	const int& getInt(string key);

protected:
	//在派生类构造函数中调用insertSectonKey设置section+key+默认值
	virtual void initSectionKey() = 0;
	void insertSectonKey(string section, string key, string defineValue);
	void insertSectonKey(string section, string key, int defineValue);
	

纯虚函数initSectionKey是为了满足不同配置文件的差异化设置,文件名+一套{section+key}。实例化派生类后, 需要调用read()函数加载数据。调用set、get设置获取数据。设置获取数据略显麻烦,需要传入key值。所以我会把key值全部定义成宏。如: 井define IP_KEY_INI ”IP“。这样就避免每次手写,还容易写错!!!吐槽:虽然这样还是比直接把所有数据定义为成员变量麻烦。但为了复用啊,每新增一个配置文件,我只需派生一个基类,重写下initSectionKey就好了。

2.3、成员变量

	string	m_filePath;		//ps ".\config\file.ini"
	string	m_errStr;       //"err"
	int		m_errInt;       //-1

	map<string, string>	m_keySection;   //key,section
	map<string, string> m_keyString;    //key,字符串数据
	map<string, int>	m_keyInt;       //key,整形数据

惊不惊讶,奇不奇怪。key对应section,key对应数据。这几个数据都要在initSectionKey中赋值。read()时会先调用initSectionKey,然后for(auto& iter : m_keyString ) 获取字符串数据,同理,获取整形数据。

2.4、完整代码
FileIni.h

#pragma once

#include <map>
using namespace std;

class FileIni
{
public:
	FileIni();
	~FileIni() { }

	//读取,让调用者知道是否成功。
	bool read();

	//设置本地+文件
	void set(string key, string value);
	void set(string key, int value);

	const string& getString(string key);
	const int& getInt(string key);

protected:
	//在派生类构造函数中调用insertSectonKey设置 section+key+默认值
	virtual void initSectionKey() = 0;
	void insertSectonKey(string section, string key, string defineValue);
	void insertSectonKey(string section, string key, int defineValue);

private:
	string	m_filePath;		//ps ".\config\file.ini"
	string	m_errStr;
	int	m_errInt;

	map<string, string>	m_keySection;
	map<string, string> m_keyString;
	map<string, int>	m_keyInt;
};

FileIni.cpp

#include "FileIni.h"
#include <shlwapi.h>

#pragma comment(lib, "shlwapi.lib")

FileIni::FileIni()
	: m_filePath("")
	, m_errStr("err")
	, m_errInt(-1)
{}

bool FileIni::read()
{
	m_keySection.clear();
	m_keyString.clear();
	m_keyInt.clear();
	initSectionKey();

	if (m_filePath.empty() || m_keySection.empty())
	{
		return false;
	}

	if (!PathFileExists(m_filePath.c_str()))
	{
		return false;
	}

	for (auto& iter : m_keyString)
	{
		const string& key = iter.first;
		string& section = m_keySection[key];
		string& define = iter.second;

		char buff[1024] = { 0 };
		GetPrivateProfileString(section.c_str(), key.c_str(), define.c_str(), buff, sizeof(buff), m_filePath.c_str());
		iter.second = buff;
	}

	for (auto& iter : m_keyInt)
	{
		const string& key = iter.first;
		string& section = m_keySection[key];
		int& define = iter.second;

		iter.second = GetPrivateProfileInt(section.c_str(), key.c_str(), define, m_filePath.c_str());
	}

	return true;
}

void FileIni::set(string key, string value)
{
	auto iter = m_keyString.find(key);
	if (iter != m_keyString.end())
	{
		iter->second = value;

		string& section = m_keySection[key];
		WritePrivateProfileString(section.c_str(), key.c_str(), value.c_str(), m_filePath.c_str());
	}
}

void FileIni::set(string key, int value)
{
	auto iter = m_keyInt.find(key);
	if (iter != m_keyInt.end())
	{
		iter->second = value;

		string& section = m_keySection[key];
		char valueStr[64] = { 0 };
		_itoa_s(value, valueStr, 10);
		WritePrivateProfileString(section.c_str(), key.c_str(), valueStr, m_filePath.c_str());
	}
}

const string& FileIni::getString(string key)
{
	auto iter = m_keyString.find(key);
	if (iter != m_keyString.end())
	{
		return iter->second;
	}

	return m_errStr;
}

const int& FileIni::getInt(string key)
{
	auto iter = m_keyInt.find(key);
	if (iter != m_keyInt.end())
	{
		return iter->second;
	}

	return m_errInt;
}

void FileIni::insertSectonKey(string section, string key, string defineValue)
{
	m_keySection[key] = section;
	m_keyString[key] = defineValue;
}

void FileIni::insertSectonKey(string section, string key, int defineValue)
{
	m_keySection[key] = section;
	m_keyInt[key] = defineValue;
}

积累生活的点点滴滴,不为你看到,只怕突然回忆。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值