虽然微软强烈推荐用注册表代替ini来记录软件配置,但是由于写ini文件的方便性和可读性的优势,还是让很多程序员选择把配置记录到ini文件中。但是用Windows API操作ini文件有个缺点,就是每次调用如GetPrivateProfileInt,WritePrivateProfileString等函数,都会产生一次文件打开关闭以及读写操作,并且对ini文件重新解析,这是非常低效的。所以如果需要大量的操作ini文件,例如需要读取很多配置信息以启动软件,那么这样的用法无疑会增加软件的冷启动时间。为了解决这个问题,我们就需要自己写一个模块,他能够一次性读取并且解析好ini文件。在需要读取的时候直接从内存读取,需要些的时候先全部写到内存里,最后在刷新到文件上。所以我写了一个ParseIni的类,来完成这个工作。代码如下:
#ifndef __PARSE_INI_H__
#define __PARSE_INI_H__
#include <vector>
#include <string>
#include <fstream>
#include <windows.h>
#define INI_KEY_LINE 1
#define INI_SECTION_LINE 2
#define INI_COMMENT_LINE 3
#define INI_NC_KEY_LINE 4
#define INI_WORNG_SYNTAX 0
using namespace std;
class CParseIniA {
public:
CParseIniA() {}
~CParseIniA() {}
BOOL Open(const string &IniPath;, BOOL OpenAlways = TRUE);
vector EnumSectionNames();
vector EnumKeyNamesInSection(const string &SectionName;);
string GetSectionKeyValue(const string &SectionName;, const string &KeyName;, const string &DefaultValue;);
int GetSectionKeyValueInt(const string &SectionName;, const string &KeyName;, int DefaultValue);
BOOL SetSectionKeyValueInt(const string &SectionName;, const string &KeyName;, int value, BOOL CreateNew = TRUE);
BOOL SetSectionKeyValue(const string &SectionName;, const string &KeyName;, const string &Value;, BOOL CreateNew = TRUE);
BOOL Flush();
VOID Close();
private:
ULONG SyntaxCheck(const string &KeyLine;);
vector::iterator CreateSection(const string &SectionName;);
VOID CreateKeyValue(vector::iterator it, const string &KeyName;, const string &Value;);
BOOL IsSection(string &Line;);
BOOL SetKeyValue(string &Line;, const string &Value;);
string GetKeyValue(string &Line;);
string GetSectionName(string &Line;);
string GetKeyName(string &Line;);
string trim(const string& s ,const string& drop = " ");
vector m_IniContext;
string m_IniPath;
};
inline BOOL CParseIniA::Open( const string &IniPath;, BOOL OpenAlways)
{
ifstream IniFile(IniPath.c_str());
INT FileSize;
vector::iterator it;
if (!IniFile.is_open()) {
if (!OpenAlways) {
return FALSE;
}
m_IniPath = IniPath;
return TRUE;
}
m_IniPath = IniPath;
IniFile.seekg(0, std::ios_base::end);
FileSize = IniFile.tellg();
IniFile.seekg(0, std::ios_base::beg);
if (FileSize == 0) {
return TRUE;
}
while (IniFile) {
string IniLine;
getline(IniFile, IniLine);
m_IniContext.push_back(IniLine);
}
it = m_IniContext.end();
it--;
while (trim(*it).empty()) {
m_IniContext.pop_back();
it = m_IniContext.end();
it--;
}
return TRUE;
}
inline BOOL CParseIniA::IsSection( string &Line; )
{
string SectionLine = trim(Line);
BOOL Ret = FALSE;
if (SectionLine[0] == '[' && SectionLine[SectionLine.length() - 1] == ']') {
Ret = TRUE;
}
return Ret;
}
inline vector CParseIniA::EnumSectionNames()
{
vector SectionNames;
vector::iterator it;
for (it = m_IniContext.begin(); it != m_IniContext.end(); ++it) {
if (IsSection(*it)) {
SectionNames.push_back(GetSectionName(*it));
}
}
return SectionNames;
}
inline vector CParseIniA::EnumKeyNamesInSection(const string &SectionName; )
{
vector::iterator it;
vector KeyNames;
ULONG ScanState = 0;
for (it = m_IniContext.begin(); it != m_IniContext.end(); ++it) {
if (ScanState == 0) {
if (!IsSection(*it) || GetSectionName(*it) != SectionName) {
continue;
}
ScanState = 1;
}
else if (ScanState == 1) {
if (IsSection(*it)) {
break;
}
KeyNames.push_back(GetKeyName(*it));
}
}
return KeyNames;
}
inline string CParseIniA::GetSectionName( string &Line; )
{
INT Count = Line.length();
INT i;
BOOL Start = FALSE;
string SectionName;
for (i = 0; i < Count; i++) {
if (Line[i] == '[') {
Start = TRUE;
}
else if (Line[i] == ']') {
if (Start) {
break;
}
}
else {
if (Start) {
SectionName += Line[i];
continue;
}
}
}
return SectionName;
}
inline string CParseIniA::GetKeyName( string &Line; )
{
string KeyName;
KeyName = Line.substr(0, Line.find_first_of('='));
return trim(KeyName);
}
inline string CParseIniA::trim(const string& s, const string& drop)
{
string t(s);
string r = t.erase(t.find_last_not_of(drop) + 1);
return r.erase(0,r.find_first_not_of(drop));
}
inline int CParseIniA::GetSectionKeyValueInt( const string &SectionName;, const string &KeyName;, int DefaultValue )
{
char DefaultValueString[32] = {0};
sprintf_s(DefaultValueString, "%d", DefaultValue);
string ValueString = GetSectionKeyValue(SectionName, KeyName, DefaultValueString);
return atoi(ValueString.c_str());
}
inline string CParseIniA::GetSectionKeyValue(const string &SectionName;, const string &KeyName;, const string &DefaultValue; )
{
vector::iterator it;
ULONG ScanState = 0;
string Value = DefaultValue;
for (it = m_IniContext.begin(); it != m_IniContext.end(); ++it) {
if (ScanState == 0) {
if (!IsSection(*it) || GetSectionName(*it) != SectionName) {
continue;
}
ScanState = 1;
}
else if (ScanState == 1) {
if (IsSection(*it)) {
break;
}
if (SyntaxCheck(*it) != INI_KEY_LINE) {
continue;
}
if (GetKeyName(*it) == KeyName) {
Value = GetKeyValue(*it);
}
}
}
return Value;
}
inline string CParseIniA::GetKeyValue( string &Line; )
{
string KeyName;
KeyName = Line.substr(Line.find_first_of('=') + 1);
return trim(KeyName);
}
inline BOOL CParseIniA::SetKeyValue( string &Line;, const string &Value; )
{
INT Pos = Line.find_first_of('=');
if (Pos == string::npos) {
return FALSE;
}
Pos = Line.find_first_not_of(' ', Pos + 1);
if (Pos == string::npos) {
Pos = Line.find_first_of('=') + 1;
}
Line.erase(Pos);
Line += Value;
return TRUE;
}
inline BOOL CParseIniA::SetSectionKeyValueInt( const string &SectionName;, const string &KeyName;, int Value, BOOL CreateNew /*= TRUE*/ )
{
char ValueString[32] = {0};
sprintf_s(ValueString, "%d", Value);
return SetSectionKeyValue(SectionName, KeyName, ValueString, CreateNew);
}
inline BOOL CParseIniA::SetSectionKeyValue( const string &SectionName;, const string &KeyName;, const string &Value;, BOOL CreateNew )
{
vector::iterator it;
ULONG ScanState = 0;
BOOL Ret = FALSE;
for (it = m_IniContext.begin(); it != m_IniContext.end(); ++it) {
if (ScanState == 0) {
if (!IsSection(*it) || GetSectionName(*it) != SectionName) {
continue;
}
ScanState = 1;
}
else if (ScanState == 1) {
if (IsSection(*it)) {
break;
}
if (SyntaxCheck(*it) == INI_KEY_LINE || SyntaxCheck(*it) == INI_NC_KEY_LINE) {
if (GetKeyName(*it) == KeyName) {
Ret = SetKeyValue(*it, Value);
}
}
}
}
if (CreateNew && !Ret) {
if (ScanState == 0) {
it = CreateSection(SectionName);
CreateKeyValue(it, KeyName, Value);
}
else if (ScanState == 1) {
it--;
CreateKeyValue(it, KeyName, Value);
}
Ret = TRUE;
}
return Ret;
}
inline BOOL CParseIniA::Flush()
{
ofstream IniFile(m_IniPath.c_str());
vector::iterator it;
if (!IniFile.is_open()) {
return FALSE;
}
for (it = m_IniContext.begin(); it != m_IniContext.end(); ++it) {
IniFile << it->c_str() << endl;
}
return TRUE;
}
inline VOID CParseIniA::Close()
{
}
inline vector::iterator CParseIniA::CreateSection( const string &SectionName; )
{
string FullSectionName;
vector::iterator it;
FullSectionName += '[';
FullSectionName += SectionName;
FullSectionName += ']';
m_IniContext.push_back(FullSectionName);
it = m_IniContext.begin() + m_IniContext.size() - 1;
return it;
}
inline VOID CParseIniA::CreateKeyValue( vector::iterator it, const string &KeyName;, const string &Value; )
{
string KeyInfo;
KeyInfo += KeyName;
KeyInfo += " = ";
KeyInfo += Value;
while (it != m_IniContext.begin()) {
if (!trim(*it).empty()) {
break;
}
it--;
}
m_IniContext.insert(it + 1, KeyInfo);
}
inline ULONG CParseIniA::SyntaxCheck( const string &KeyLine; )
{
string Line = trim(KeyLine);
INT Pos, CommentPos1, CommentPos2;
string KeyName;
string Value;
if (IsSection(Line)) {
return INI_SECTION_LINE;
}
else if (Line[0] == ';' || Line[0] == '#') {
return INI_COMMENT_LINE;
}
else {
Pos = Line.find_first_of('=');
if (string::npos == Pos) {
return INI_WORNG_SYNTAX;
}
KeyName = trim(Line.substr(0, Pos));
if (KeyName.empty()) {
return INI_WORNG_SYNTAX;
}
Value = trim(Line.substr(Pos + 1));
if (Value.empty()) {
return INI_NC_KEY_LINE;
}
CommentPos1 = Value.find_first_of(';');
CommentPos2 = Value.find_first_of('#');
if (CommentPos1 == string::npos && CommentPos2 == string::npos) {
return INI_KEY_LINE;
}
CommentPos1 = CommentPos1 < CommentPos2 ? CommentPos1 : CommentPos2;
if (Value.erase(CommentPos1).empty()) {
return INI_NC_KEY_LINE;
}
return INI_KEY_LINE;
}
}
#endif