工作中需要经常读取INI配置文件,自己写了一个简单的类来做这些重复工作,该类简单实用,在我的工作中发挥了较好效用,下面贴出代码,供有需要的人参考。
CommonDefs.h文件
//=============================================================================
/**
* @file CommonDefs.h
*
* $Id: CommonDefs.h version 1.0 2007-11-20 $
*
* @author Zhao Jun <zjwaszx@gmail.com>
*
* Copyright (c) 2008 by <ZhaoJun>
*/
//=============================================================================
#ifndef __COMMOM_DEFS_H__
#define __COMMOM_DEFS_H__
///
/// 名字空间宏声明
///
#ifdef HAVE_LTK_NAMESPACE
namespace NS_Lightweight_ToolKit
{
}
namespace LTK = NS_Lightweight_ToolKit;
/// 名字空间开始宏声明
# define __LTK_BEGIN namespace NS_Lightweight_ToolKit {
/// 名字空间结束宏声明
# define __LTK_END }
/// 使用名字空间宏声明
# define __USE_NS_LTK using namespace NS_Lightweight_ToolKit;
#else
# define __LTK_BEGIN
# define __LTK_END
# define __USE_NS_LTK
#endif
/// 定义内联函数关键字
#define INLINE inline
__LTK_BEGIN
///
/// 常量定义
///
/// 一行的最大字节数
static const int MAX_LINE_BYTE = 2048;
///
/// 函数返回值类型定义
///
/// 定义函数返回代码类型
typedef int RET_CODE;
/// 函数成功返回代码
static const RET_CODE RET_CODE_OK = 0;
/// 函数失败返回代码
static const RET_CODE RET_CODE_ERR = -1;
__LTK_END
#endif // __COMMOM_DEFS_H__
IniProfile.h文件
//=============================================================================
/**
* @file IniProfile.h
*
* $Id: IniProfile.h version 1.0 2007-11-20 $
*
* @author Zhao Jun <zjwaszx@gmail.com>
*
* Copyright (c) 2008 by <ZhaoJun>
*/
//=============================================================================
#ifndef __INI_PROFILE_H__
#define __INI_PROFILE_H__
#include <vector>
#include <utility>
#include <iostream>
#include <fstream>
#include <string>
#include <map>
#include "CommonDefs.h"
__LTK_BEGIN
using std::vector;
using std::pair;
using std::cout;
using std::ifstream;
using std::string;
using std::map;
using std::endl;
using std::ofstream;
/**
@brief 读取INI配置文件的类.
一个专门用于读取INI配置文件的类.
*/
class CIniProfile
{
/// INI配置文件的一个键值对.
typedef pair<string, string> INI_ITEM;
/// INI配置文件的一个配置段.
class CIniSection
{
friend class CIniProfile;
public:
string strSection; ///< INI配置段名
vector<INI_ITEM> vecSection; ///< INI配置项目对
};
public:
/// 默认构造函数.
CIniProfile();
/// 析构函数,什么也不做.
~CIniProfile();
/**
@brief 读取配置文件内容.
@param strProfile, 配置文件路径
@return bool,
true --读取成功
false --读取失败
*/
bool LoadConfig(const string &strProfile);
/**
@brief 获取配置文件中某一项的值.
@param strSection, INI分段名
@param strKey, INI项目名
@param strValue, 保存有INT值,输出
@return bool,
true --获取成功
false --获取失败
*/
bool GetItem(const string &strSection, const string &strKey, string &strValue);
/**
@brief 转换到XML文件格式.
@param strXmlFilePath, 转换后的XML配置文件名
*/
void ToXMLFormat(const string &strXmlFilePath);
protected:
/**
@brief 解析配置文件的一行内容.
@return int,
RET_CODE_OK --解析成功
RET_CODE_ERR --解析失败
*/
RET_CODE ParseLine(string strLine);
/// 将字符串两边的空格和TAB去掉.
string Trim(const string &strIn);
private:
/// 配置文件路径
string m_strProfile;
/// 读取到的配置文件项目
vector<CIniSection> m_iniSections;
/// 已读取的配置文件的行数
int m_nLineCount;
/// 调试函数,打印读取到的配置文件项目内容.
void Dump();
};
__LTK_END
#include "impl/IniProfile_impl.h"
#endif // __INI_PROFILE_H__
IniProfile_impl.h文件
__LTK_BEGIN
INLINE
CIniProfile::CIniProfile()
{
m_nLineCount = 0;
}
INLINE
CIniProfile::~CIniProfile()
{
}
INLINE
bool CIniProfile::LoadConfig(const string &strProfile)
{
m_iniSections.clear();
m_nLineCount = 0;
m_strProfile = strProfile;
char szLine[MAX_LINE_BYTE] = { 0 };
ifstream ifs(m_strProfile.c_str());
while (ifs.getline(szLine, MAX_LINE_BYTE, '/n'))
{
m_nLineCount++;
string strLine(szLine);
switch (ParseLine(strLine))
{
case RET_CODE_OK:
break;
case RET_CODE_ERR:
cout<<"Profile Error at line "<<m_nLineCount<<" : "<<strLine<<endl;
return false;
break;
default:
break;
}
}
return true;
}
INLINE
bool CIniProfile::GetItem(const string &strSection, const string &strKey, string &strValue)
{
for (vector<CIniSection>::iterator iter = m_iniSections.begin();
iter != m_iniSections.end();
++iter)
{
if (iter->strSection == strSection)
{
for (vector<INI_ITEM>::iterator iniIter = iter->vecSection.begin();
iniIter != iter->vecSection.end();
++iniIter)
{
if (iniIter->first == strKey)
{
strValue = iniIter->second;
return true;
}
}
return true;
}
}
return false;
}
INLINE
void CIniProfile::Dump()
{
for (vector<CIniSection>::iterator iter = m_iniSections.begin();
iter != m_iniSections.end();
++iter)
{
cout<<'['<<iter->strSection<<"]/n";
for (vector<INI_ITEM>::iterator iniIter = iter->vecSection.begin();
iniIter != iter->vecSection.end();
++iniIter)
{
cout<<iniIter->first<<"="<<iniIter->second<<"/n";
}
}
}
INLINE
RET_CODE CIniProfile::ParseLine(string strLine)
{
static string strSectionName = "default";
string::size_type nPos = 0;
if (strLine[0] == '#') // 注释
{
return RET_CODE_OK;
}
else if (strLine[0] == '[') // 段落
{
nPos = strLine.find(']', 1);
if (nPos == string::npos)
{
return RET_CODE_ERR;
}
else
{
string strSection = strLine.substr(1, nPos-1);
if (strSection.empty())
{
return RET_CODE_ERR;
}
else
{
CIniSection iniSection;
iniSection.strSection = strSection;
strSectionName = strSection;
m_iniSections.push_back(iniSection);
return RET_CODE_OK;
}
}
}
else if ((nPos=strLine.find('=')) != string::npos) // INI项
{
string strLeft = strLine.substr(0, nPos);
strLeft = Trim(strLeft);
if (strLeft.empty())
{
return RET_CODE_ERR;
}
else
{
string strRight = strLine.substr(nPos+1);
strRight = Trim(strRight);
if (strRight.empty())
{
return RET_CODE_ERR;
}
else
{
for (vector<CIniSection>::iterator iter = m_iniSections.begin();
iter != m_iniSections.end();
++iter)
{
if (iter->strSection == strSectionName)
{
iter->vecSection.push_back(make_pair(strLeft, strRight));
break;
}
}
return RET_CODE_OK;
}
}
}
else if (strLine.find_first_not_of(" /t/r/n") != string::npos) // 其他情况
{
return RET_CODE_ERR;
}
else // 空行
{
return RET_CODE_OK;
}
}
INLINE
string CIniProfile::Trim(const string &strInput)
{
string str = strInput;
string::iterator i = str.begin();
for (; i != str.end(); i++)
{
if (!isspace(*i))
{
break;
}
}
if (i == str.end()) // 空串,直接返回
{
str.clear();
return str;
}
else
{
str.erase(str.begin(), i);
}
// str不可能是空串了
for (i = str.end() - 1; ;i--)
{
if (!isspace(*i))
{
str.erase(i + 1, str.end());
break;
}
if (i == str.begin())
{
str.clear();
break;
}
}
return str;
}
INLINE
void CIniProfile::ToXMLFormat(const string &strXmlFilePath)
{
string strOut = "<?xml version=/"1.0/" encoding=/"ANSI/"?>/n";
strOut += "<Profile>/n";
for (vector<CIniSection>::iterator iter = m_iniSections.begin();
iter != m_iniSections.end();
++iter)
{
strOut += "/t<" + iter->strSection + ">/n";
for (vector<INI_ITEM>::iterator iniIter = iter->vecSection.begin();
iniIter != iter->vecSection.end();
++iniIter)
{
strOut += "/t/t<" + iniIter->first;
strOut += " value=/"" + iniIter->second;
strOut += "/"/>/n";
}
strOut += "/t</" + iter->strSection + ">/n";
}
strOut += "</Profile>/n";
ofstream ofs(strXmlFilePath.c_str(), ofstream::app);
ofs.write(strOut.c_str(), strOut.length());
}
__LTK_END
main.cpp文件
#include <string>
#include <iostream>
#include "IniProfile.h"
using namespace std;
int main(int, char *[])
{
CIniProfile profile;
profile.LoadConfig("test.etc");
string strValue;
cout<<"the [test] section:/n";
profile.GetItem("test", "normal_1", strValue);
cout<<"normal_1 = ";
cout<<"["<<strValue<<"]"<<endl;
profile.GetItem("test", "normal_2", strValue);
cout<<"normal_2 = ";
cout<<"["<<strValue<<"]"<<endl;
profile.GetItem("test", "normal_3", strValue);
cout<<"normal_3 = ";
cout<<"["<<strValue<<"]"<<endl;
profile.GetItem("test", "normal_4", strValue);
cout<<"normal_4 = ";
cout<<"["<<strValue<<"]"<<endl;
cout<<"/nthe [others] section:"<<endl;
profile.GetItem("others", "name", strValue);
cout<<"name = ";
cout<<"["<<strValue<<"]"<<endl;
profile.GetItem("others", "hobbies", strValue);
cout<<"hobbies = ";
cout<<"["<<strValue<<"]"<<endl;
return 0;
};
配置文件
#this is a testing ini file.
[test]
#this is comment for normal_1
normal_1=value_1
#this is comment for normal_2
normal_2 = value_2
normal_3 = value_3
normal_4 = hhh jjjjj
PS:插入代码时,没有C++风格的,只有直接粘贴了,有点难看,也没有整理格式了。