ini文件另一种读取办法
Windows下的ini文件的读取可以使用系统提供的api来实现
GetPrivateProfileString
GetPrivateProfileInt
...
实际应用中, 如果不使用一种统一的方法来包装一下会让源代码看起来很乱。
所以,需要设计一个方便,美观,直观的配置文件操作类!
原则是代码好看,容易维护
需求:
直观的调用形式
实现潜规则
满足各类数据(实现api常用的数据类型)
解释:
- 直观的调用形式是什么意思
以减少键盘输入和见文知意为原则的设计方式,把长函数名变为符号。用符号来表示操作
- 潜规则
在配置ini访问中的潜规则是
1. Wiki上对ini的定义
INI文件有节的概念节用 [] 包围,类似数据中的表名称,如
[startup]
名称/值对,类似数据库表中的字段,如
TargetIP=10.0.0.1
注释, 以";"为注释的开始,到行尾,如
MenuOne=File... ; 菜单的第一项文字描述
2. Windows系统中操作ini文件时有#开头的行是忽略的,如:#对打印机的设置
3. 可配置是否忽略Key的大小写
4. 符合语义的读取和写入
在windows api下GetPrivateProfile/WritePrivateProfileXXXX在调用该方法时同步执行对ini文件的操作
- 满足各类数据,在ini中常用的数据有两种,字符串和整型数据,满足所有数据类型显然不现实,可以在之后根据不同需要进行扩展
设计使用方法:
1. 读取
CIniAccessor accessor(_T("config.ini")); std::wstring strMenuOne = accessor[_T("startup")][_T("MenuOne")](_T("DefaultMenuItem"));
2. 写入
3. 更新
CIniAccessor accessor(_T("config.ini")); accessor[_T("startup")][_T("TargetIP")] = _T("10.0.0.100");
3. 更新
CIniAccessor accessor(_T("config.ini")); accessor.Update(); // 从磁盘上更新 accessor.Commit(); // 写入磁盘
下面是数据结构
- 基础类
typedef struct tagAccessorData { union VALUETYPE { LONG longValue; TCHAR * pszValue; }value; enum{TYPE_EMPTY, TYPE_LONG, TYPE_CHAR}valuetype; tagAccessorData():valuetype(TYPE_EMPTY){} }ACCESSORDATA;
- 辅助工具类
class CCoAccessorImpl:public ACCESSORDATA { private: TCHAR m_szTemp[30]; public: CCoAccessorImpl() { valuetype = TYPE_EMPTY; value.longValue = 0; } CCoAccessorImpl(const CCoAccessorImpl & acc) { valuetype = acc.valuetype; if(acc.valuetype == TYPE_CHAR) { value.pszValue = new TCHAR[_tcslen(acc.value.pszValue) + 1]; ZeroMemory(value.pszValue, sizeof(TCHAR) * (_tcslen(acc.value.pszValue) + 1)); _tcscpy(value.pszValue, acc.value.pszValue); }else { value.longValue = acc.value.longValue; } } CCoAccessorImpl(const LONG lValue) { valuetype = TYPE_LONG; value.longValue = lValue; } CCoAccessorImpl(LPCTSTR lpszValue) { valuetype = TYPE_CHAR; value.pszValue = new TCHAR[_tcslen(lpszValue) + 1]; ZeroMemory(value.pszValue, sizeof(TCHAR) * (_tcslen(lpszValue) + 1)); _tcscpy(value.pszValue, lpszValue); } ~CCoAccessorImpl() { if(valuetype == TYPE_CHAR) delete [] value.pszValue; } CCoAccessorImpl & operator = (const CCoAccessorImpl& acc) { if(valuetype == TYPE_CHAR) delete [] value.pszValue; value.longValue = 0; valuetype = acc.valuetype; if(acc.valuetype == TYPE_CHAR) { value.pszValue = new TCHAR[_tcslen(acc.value.pszValue) + 1]; ZeroMemory(value.pszValue, sizeof(TCHAR) * (_tcslen(acc.value.pszValue) + 1)); _tcscpy(value.pszValue, acc.value.pszValue); }else { value.longValue = acc.value.longValue; } return *this; } CCoAccessorImpl & operator = (const LONG lValue) { if(valuetype == TYPE_CHAR) delete [] value.pszValue; valuetype = TYPE_LONG; value.longValue = lValue; return *this; } CCoAccessorImpl & operator = (LPCTSTR lpszValue) { if(valuetype == TYPE_CHAR) delete [] value.pszValue; valuetype = TYPE_CHAR; value.pszValue = new TCHAR[_tcslen(lpszValue) + 1]; ZeroMemory(value.pszValue, sizeof(TCHAR) * (_tcslen(lpszValue) + 1)); _tcscpy(value.pszValue, lpszValue); return *this; } operator LPCTSTR () { switch(valuetype) { case TYPE_LONG: return _ltot(value.longValue, m_szTemp, 10); case TYPE_CHAR: return value.pszValue; } return _T(""); } operator LONG () { switch(valuetype) { case TYPE_LONG: case TYPE_EMPTY: return value.longValue; } return _ttol(value.pszValue); } CCoAccessorImpl operator ()(LPCTSTR lpsz) //default value { if(valuetype == TYPE_EMPTY) return CCoAccessorImpl(lpsz); return *this; } CCoAccessorImpl operator ()(LONG lValue) //default value { if(valuetype == TYPE_EMPTY) return CCoAccessorImpl(lValue); return *this; } }; typedef std::basic_string<TCHAR> TCharArray; struct less { bool operator()(const TCharArray& _Left, const TCharArray& _Right) const { return _tcsicmp(_Left.c_str(), _Right.c_str()) < 0; } }; template<class ValueType, BOOL bSensitive> class CKeyValueArray:public std::map<TCharArray, ValueType, less> { public: CKeyValueArray(){} ~CKeyValueArray(){} ValueType & operator[](TCharArray charArray) { if(!bSensitive) _tcsupr((TCHAR*)charArray.data()); return std::map<TCharArray, ValueType, less>::operator[](charArray); } }; // 读文件操作 template<class Storage> struct iniparser { BOOL operator()(Storage & store, LPCTSTR lpszFilePath) { HANDLE hFile = CreateFile(lpszFilePath, // file to open GENERIC_READ, // open for reading FILE_SHARE_READ, // share for reading NULL, // default security OPEN_EXISTING, // existing file only FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { return FALSE; } TCHAR sz[2] = {0}; DWORD dwRead = 0; TCharArray tcaLine; TCharArray tcaSectionName; struct foo { static void parse(Storage & store, TCharArray & tcaSectionName, TCharArray & tcaLine) { if(!tcaLine.size()) return; // parse [] TCHAR szComment[MAX_PATH] = {0}; if(tcaLine.at(0) == _T('#')) return; TCharArray sSec; if(_stscanf(tcaLine.c_str(), _T("[%[^]]]"), (TCHAR*)sSec.assign(MAX_PATH,0).data())) { tcaSectionName = sSec; } else { // parse key = value TCHAR szKey[MAX_PATH] = {0}; TCHAR szValue[MAX_PATH] = {0}; if(2 == _stscanf(tcaLine.c_str(), _T("%[^=]=%[^\0]"), szKey, szValue)) { store[tcaSectionName][szKey] = szValue; } } } }; while(ReadFile(hFile, sz, sizeof(TCHAR),&dwRead, NULL)) { if(!dwRead) break; if(!(sz[0] == _T('\r') || sz[0] == _T('\n'))) { tcaLine.push_back(sz[0]); continue; } foo::parse(store, tcaSectionName, tcaLine); tcaLine.clear(); tcaLine.reserve(); } CloseHandle(hFile); foo::parse(store, tcaSectionName, tcaLine); return TRUE; } }; // 写文件操作 template<class Storage> struct inipersistor { BOOL operator()(Storage & store, LPCTSTR lpszFilePath) { HANDLE hFile = CreateFile(lpszFilePath, // file to open GENERIC_WRITE, // open for reading FILE_SHARE_WRITE, // share for reading NULL, // default security OPEN_ALWAYS, // existing file only FILE_ATTRIBUTE_NORMAL, // normal file NULL); // no attr. template if (hFile == INVALID_HANDLE_VALUE) { return FALSE; } for(Storage::iterator it = store.begin();it != store.end();it++) { TCharArray tcaSectionName = (*it).first; Storage::mapped_type & kva = (*it).second; DWORD dwWritten = 0; WriteFile(hFile, _T("["), sizeof(TCHAR), &dwWritten, NULL); WriteFile(hFile, tcaSectionName.c_str(), sizeof(TCHAR) * tcaSectionName.size(), &dwWritten, NULL); WriteFile(hFile, _T("]\r\n"), sizeof(TCHAR) * 3, &dwWritten, NULL); for(Storage::mapped_type::iterator itKeyVal = kva.begin();itKeyVal != kva.end();itKeyVal++) { TCharArray tcaKey = (*itKeyVal).first; TCharArray tcaVal = (*itKeyVal).second; WriteFile(hFile, tcaKey.c_str(), sizeof(TCHAR) * tcaKey.size(), &dwWritten, NULL); WriteFile(hFile, _T("="), sizeof(TCHAR), &dwWritten, NULL); WriteFile(hFile, tcaVal.c_str(), sizeof(TCHAR) * tcaVal.size(), &dwWritten, NULL); WriteFile(hFile, _T("\r\n"), sizeof(TCHAR) * 2, &dwWritten, NULL); } } CloseHandle(hFile); return TRUE; } };
- 访问类
template< class ValueType = CCoAccessorImpl, BOOL bSensitive = FALSE, class Parser = iniparser<std::map<TCharArray, CKeyValueArray<ValueType,bSensitive>,less > >, class Persistor = inipersistor<std::map<TCharArray, CKeyValueArray<ValueType,bSensitive>,less > > > class TIniAccessor { public: private: Parser _parser; Persistor _persistor; TCharArray m_szFileName; public: TIniAccessor(LPCTSTR lpsz):_parser(Parser()),_persistor(Persistor()) { m_szFileName = lpsz; _parser(m_sectionarray, m_szFileName.c_str()); } BOOL Update() { return _parser(m_sectionarray, m_szFileName.c_str()); } BOOL Commit(LPCTSTR lpszSaveIniFile = NULL) { TCharArray tca = m_szFileName; if(lpszSaveIniFile) tca = lpszSaveIniFile; return _persistor(m_sectionarray, tca.c_str()); } ~TIniAccessor(){} private: typedef std::map<TCharArray, CKeyValueArray<ValueType,bSensitive>, less> SectionArray; SectionArray m_sectionarray; public: CKeyValueArray<ValueType,bSensitive> & operator [](TCharArray charArray) { if(!bSensitive) _tcsupr((TCHAR*)charArray.data()); return m_sectionarray[charArray]; } };
- 访问类
typedef TIniAccessor<> CIniAccessor;