这篇文章简单讨论一下ini文件。
一.什么是ini文件
ini文件其实就是一种配置文件,常见于Windows的系统配置文件,当然也可以是其他用途,你的用法你说了算。
二.ini文件的格式一般是什么样的
看个例子
;这是注释 [section1] key1=value1 key2=value2 [section2] key3=value3 key4=value4
ini文件包括节(section)、键值对(通常称为参数,parameter)和注释(comment)。
1.节
1.每一个section包含若干个parameter。
2.每一个section独占一行,名称由[]包围,比如[sectionName]。
3.每一个section的生效范围,从当前section开始到下一个section的开始(或者文件结尾),这其中所有的parameter都属于这个section。
4.section不应该重复。
2.参数
1.parameter以键值对的形式存在,比如key=value。
2.同一个section中的parameter不应该重复。
3.注释
1.注释用;表示。
2.注释独占一行。
三.C++实现ini文件的解析
重点来了,这里展示一种C++解析ini文件的简易代码写法,主要是描述一种解析的思维,大致测试过了。
直接看代码
//inifile.h #ifndef INIFILE_H #define INIFILE_H #include <iostream> #include <string> #define ERR_MES_1 "输入值不合法" #define ERR_MES_2 "打开文件失败" #define ERR_MES_3 "配置项不存在" const char TYPE_NULL = '0'; const char TYPE_SECTION = '1'; const char TYPE_PARAMETER = '2'; const char TYPE_COMMENT = '3'; typedef struct IniNode { char m_Type; std::string m_Text; IniNode* m_pPrev; IniNode* m_pNext; }IniNode, * pIniNode; typedef struct IniSec { pIniNode m_pSection; pIniNode m_pParameter; std::string m_SectionText; std::string m_ParameterText; }IniSec, * pIniSec; class IniFile { public: IniFile(); ~IniFile(); bool ReadIniFile(const char* FilePathName); bool WriteIniFile(const char* FilePathName); bool WriteParameter(const char* Section, const char* Key, const char* Value); bool WriteParameter(const char* Section, const char* Key, const bool Value); bool WriteParameter(const char* Section, const char* Key, const int Value); bool WriteParameter(const char* Section, const char* Key, const double Value); std::string ReadParameter(const char* Section, const char* Key, const char* Default); bool ReadParameter(const char* Section, const char* Key, const bool Default); int ReadParameter(const char* Section, const char* Key, const int Default); double ReadParameter(const char* Section, const char* Key, const double Default); bool DeleteParameter(const char* Section, const char* Key); bool DeleteSection(const char* Section); int GetErrCode(); std::string GetErrMes(); protected: void FreeIniList(); void CreateIniNode(); void Trim(char* Buffer); pIniNode FindSection(const char* Section); pIniSec FindParameter(const char* Section, const char* Key); void AddIniNode(char Type, const char* Text); bool WriteParameterPublic(const char* Section, const char* Key, const char* Value); std::string ReadParameterPublic(const char* Section, const char* Key, const char* Default); private: FILE* m_pIniFileHandle; pIniNode m_pIniList; pIniNode m_pCurIniNode; int m_LastErrCode; std::string m_LastErrMes; }; #endif // !INIFILE_H
//inifile.cpp #include "inifile.h" IniFile::IniFile() { m_LastErrCode = 0; m_LastErrMes = ""; m_pCurIniNode = nullptr; m_pIniFileHandle = nullptr; m_pIniList = nullptr; } IniFile::~IniFile() { FreeIniList(); fclose(m_pIniFileHandle); } int IniFile::GetErrCode() { return m_LastErrCode; } std::string IniFile::GetErrMes() { return m_LastErrMes; } bool IniFile::ReadIniFile(const char* FilePathName) { if (!strcmp(FilePathName, "")) { m_LastErrCode = 1; m_LastErrMes = ERR_MES_1; return false; } if (!(m_pIniFileHandle = fopen(FilePathName, "r"))) { m_LastErrCode = 2; m_LastErrMes = ERR_MES_2; return false; } FreeIniList(); char filebuf[256] = { 0 }; char* pchr = nullptr; while (fgets(filebuf, 256, m_pIniFileHandle)) { Trim(filebuf); CreateIniNode(); if (';' == filebuf[0]) { m_pCurIniNode->m_Type = TYPE_COMMENT; } else if ('[' == filebuf[0] && strchr(filebuf, ']')) { m_pCurIniNode->m_Type = TYPE_SECTION; } else if (strchr(filebuf, '=')) { m_pCurIniNode->m_Type = TYPE_PARAMETER; } else { m_pCurIniNode->m_Type = TYPE_NULL; } m_pCurIniNode->m_Text = filebuf; } fclose(m_pIniFileHandle); return true; } bool IniFile::WriteIniFile(const char* FilePathName) { if (!strcmp(FilePathName, "")) { m_LastErrCode = 1; m_LastErrMes = ERR_MES_1; return false; } char FilePathNameBat[256] = { 0 }; strcpy(FilePathNameBat, FilePathName); strcat(FilePathNameBat, ".bak"); FILE* FileIniTemp = fopen(FilePathName, "r"); FILE* FileBatTemp = fopen(FilePathNameBat, "w"); if (!FileIniTemp || !FileBatTemp) { m_LastErrCode = 2; m_LastErrMes = ERR_MES_2; return false; } char FileStr[256] = { 0 }; while (fgets(FileStr, 256, FileIniTemp)) { fprintf(FileBatTemp, "%s", FileStr); } fclose(FileIniTemp); fclose(FileBatTemp); if (!(m_pIniFileHandle = fopen(FilePathName, "w"))) { m_LastErrCode = 2; m_LastErrMes = ERR_MES_2; return false; } m_pCurIniNode = m_pIniList; while (m_pCurIniNode) { fprintf(m_pIniFileHandle, "%s\n", m_pCurIniNode->m_Text.data()); m_pCurIniNode = m_pCurIniNode->m_pNext; } fclose(m_pIniFileHandle); return true; } bool IniFile::WriteParameter(const char* Section, const char* Key, const char* Value) { return WriteParameterPublic(Section, Key, Value); } bool IniFile::WriteParameter(const char* Section, const char* Key, const bool Value) { char StrValue[256] = { 0 }; itoa(Value, StrValue, 2); return WriteParameterPublic(Section, Key, StrValue); } bool IniFile::WriteParameter(const char* Section, const char* Key, const int Value) { char StrValue[256] = { 0 }; itoa(Value, StrValue, 10); return WriteParameterPublic(Section, Key, StrValue); } bool IniFile::WriteParameter(const char* Section, const char* Key, const double Value) { char StrValue[256] = { 0 }; sprintf_s(StrValue, "%f", Value); return WriteParameterPublic(Section, Key, StrValue); } std::string IniFile::ReadParameter(const char* Section, const char* Key, const char* Default) { return ReadParameterPublic(Section, Key, Default); } bool IniFile::ReadParameter(const char* Section, const char* Key, const bool Default) { char DefaultString[2] = { 0 }; if (Default) { DefaultString[0] = '1'; } else { DefaultString[0] = '0'; } std::string RetStr = ReadParameterPublic(Section, Key, DefaultString); return atoi(RetStr.data()); } int IniFile::ReadParameter(const char* Section, const char* Key, const int Default) { char DefaultString[256] = { 0 }; itoa(Default, DefaultString, 10); std::string RetStr = ReadParameterPublic(Section, Key, DefaultString); return atoi(RetStr.data()); } double IniFile::ReadParameter(const char* Section, const char* Key, const double Default) { char DefaultString[256] = { 0 }; sprintf_s(DefaultString, "%f", Default); std::string RetStr = ReadParameterPublic(Section, Key, DefaultString); return atof(RetStr.data()); } bool IniFile::DeleteParameter(const char* Section, const char* Key) { if (!strcmp(Section, "") || !strcmp(Key, "")) { m_LastErrCode = 1; m_LastErrMes = ERR_MES_1; return false; } pIniSec pIniSecTemp = FindParameter(Section, Key); if (!pIniSecTemp) { m_LastErrCode = 3; m_LastErrMes = ERR_MES_3; return false; } m_pCurIniNode = pIniSecTemp->m_pParameter; m_pCurIniNode->m_pPrev->m_pNext = m_pCurIniNode->m_pNext; if (m_pCurIniNode->m_pNext) { m_pCurIniNode->m_pNext->m_pPrev = m_pCurIniNode->m_pPrev; } delete m_pCurIniNode; delete pIniSecTemp; return true; } bool IniFile::DeleteSection(const char* Section) { if (!strcmp(Section, "")) { m_LastErrCode = 1; m_LastErrMes = ERR_MES_1; return false; } pIniNode pSectionIniNodeTemp = FindSection(Section); if (!pSectionIniNodeTemp) { m_LastErrCode = 3; m_LastErrMes = ERR_MES_3; return false; } pIniNode pCurNextIniNode = nullptr; m_pCurIniNode = pSectionIniNodeTemp->m_pNext; while (m_pCurIniNode && m_pCurIniNode->m_Type == TYPE_PARAMETER) { pCurNextIniNode = m_pCurIniNode->m_pNext; m_pCurIniNode->m_pPrev->m_pNext = m_pCurIniNode->m_pNext; if (m_pCurIniNode->m_pNext) { m_pCurIniNode->m_pNext->m_pPrev = m_pCurIniNode->m_pPrev; } delete m_pCurIniNode; m_pCurIniNode = pCurNextIniNode; } m_pCurIniNode = pSectionIniNodeTemp; m_pCurIniNode->m_pPrev->m_pNext = m_pCurIniNode->m_pNext; if (m_pCurIniNode->m_pNext) { m_pCurIniNode->m_pNext->m_pPrev = m_pCurIniNode->m_pPrev; } delete m_pCurIniNode; return true; } void IniFile::FreeIniList() { if (nullptr == m_pIniList) { return; } pIniNode pNextIniNodeTemp = nullptr; while (nullptr != m_pIniList) { pNextIniNodeTemp = m_pIniList->m_pNext; delete m_pIniList; m_pIniList = pNextIniNodeTemp; } } void IniFile::CreateIniNode() { pIniNode pIniNodeTemp = new IniNode; memset(pIniNodeTemp, 0, sizeof(IniNode)); if (nullptr == m_pIniList) { m_pIniList = pIniNodeTemp; m_pCurIniNode = pIniNodeTemp; return; } m_pCurIniNode = m_pIniList; while (m_pCurIniNode->m_pNext) { m_pCurIniNode = m_pCurIniNode->m_pNext; } m_pCurIniNode->m_pNext = pIniNodeTemp; pIniNodeTemp->m_pPrev = m_pCurIniNode; m_pCurIniNode = pIniNodeTemp; } void IniFile::Trim(char* Buffer) { int i = 0; int len = strlen(Buffer); for (i = len - 1; i >= 0; i--) { if (' ' != Buffer[i] && '\t' != Buffer[i] && '\n' != Buffer[i]) { break; } Buffer[i] = 0; } for (i = 0; i < len; i++) { if (' ' != Buffer[i] && '\t' != Buffer[i] && '\n' != Buffer[i]) { break; } } if (0 != i) { strncpy(Buffer, Buffer + i, len - i); Buffer[len - i] = 0; } } pIniNode IniFile::FindSection(const char* Section) { m_pCurIniNode = m_pIniList; while (m_pCurIniNode) { if (!strcmp(m_pCurIniNode->m_Text.data(), Section) && m_pCurIniNode->m_Type == TYPE_SECTION) { return m_pCurIniNode; } m_pCurIniNode = m_pCurIniNode->m_pNext; } return nullptr; } pIniSec IniFile::FindParameter(const char* Section, const char* Key) { m_pCurIniNode = m_pIniList; pIniSec pIniSecTemp = new IniSec; char Buf[256] = { 0 }; char* pChr = nullptr; while (m_pCurIniNode) { if (!strcmp(m_pCurIniNode->m_Text.data(), Section) && m_pCurIniNode->m_Type == TYPE_SECTION) { pIniSecTemp->m_pSection = m_pCurIniNode; pIniSecTemp->m_SectionText = m_pCurIniNode->m_Text; m_pCurIniNode = m_pCurIniNode->m_pNext; while (m_pCurIniNode && m_pCurIniNode->m_Type == TYPE_PARAMETER) { strcpy(Buf, m_pCurIniNode->m_Text.data()); if (pChr = strchr(Buf, '=')) { *pChr = 0; Trim(Buf); if (!strcmp(Buf, Key)) { pIniSecTemp->m_pParameter = m_pCurIniNode; pIniSecTemp->m_ParameterText = m_pCurIniNode->m_Text; return pIniSecTemp; } } m_pCurIniNode = m_pCurIniNode->m_pNext; } break; } m_pCurIniNode = m_pCurIniNode->m_pNext; } delete pIniSecTemp; return nullptr; } void IniFile::AddIniNode(char Type, const char* Text) { if (Type == TYPE_SECTION) { m_pCurIniNode->m_Type = TYPE_SECTION; m_pCurIniNode->m_Text = Text; } else if (Type == TYPE_PARAMETER) { m_pCurIniNode->m_Type = TYPE_PARAMETER; m_pCurIniNode->m_Text = Text; } return; } bool IniFile::WriteParameterPublic(const char* Section, const char* Key, const char* Value) { if (!strcmp(Section, "") || !strcmp(Key, "") || !strcmp(Value, "")) { m_LastErrCode = 1; m_LastErrMes = ERR_MES_1; return false; } char Parameter[256] = { 0 }; strcpy(Parameter, Key); strcat(Parameter, "="); strcat(Parameter, Value); pIniNode pSectionNodeTemp = FindSection(Section); pIniSec pIniSecTemp = nullptr; if (!pSectionNodeTemp) { CreateIniNode(); AddIniNode(TYPE_SECTION, Section); CreateIniNode(); AddIniNode(TYPE_PARAMETER, Parameter); } else { if (!(pIniSecTemp = FindParameter(Section, Key))) { pIniNode pIniNodeTemp = new IniNode; memset(pIniNodeTemp, 0, sizeof(IniNode)); pIniNodeTemp->m_pNext = pSectionNodeTemp->m_pNext; pSectionNodeTemp->m_pNext = pIniNodeTemp; if (pIniNodeTemp->m_pNext) { pIniNodeTemp->m_pNext->m_pPrev = pIniNodeTemp; } pIniNodeTemp->m_pPrev = pSectionNodeTemp; m_pCurIniNode = pIniNodeTemp; AddIniNode(TYPE_PARAMETER, Parameter); } else { m_pCurIniNode = pIniSecTemp->m_pParameter; AddIniNode(TYPE_PARAMETER, Parameter); } } delete pIniSecTemp; pIniSecTemp = nullptr; return true; } std::string IniFile::ReadParameterPublic(const char* Section, const char* Key, const char* Default) { if (!strcmp(Section, "") || !strcmp(Key, "") || !strcmp(Default, "")) { m_LastErrCode = 1; m_LastErrMes = ERR_MES_1; return {}; } std::string Ret; pIniSec pIniSecTemp = FindParameter(Section, Key); char* pChr = nullptr; if (pIniSecTemp) { char Buf[256] = { 0 }; strcpy(Buf, pIniSecTemp->m_ParameterText.data()); if (pChr = strchr(Buf, '=')) { strcpy(Buf, pChr + 1); } Ret = Buf; } else { Ret = Default; } delete pIniSecTemp; return Ret; }
四.其他
说一个小技巧,如果担心格式写的不对,可以用熟悉的编辑器中设置文档格式这个功能调整一下,当然调整之后也要进行确认。