重写了iniparser类

在MFC里面用了一下iniparser类,发现功能不健全,又重新封装了一下,删除了上一篇日志。

MFC和boost的兼容性很烂,我为了省事专门给CString做了重载和特化。

头文件(VS一直不支持export关键字,非常蛋疼):

  1 /************************************************************************/
  2 /* Instruction: CIniParser类主要是封装了boost::property_tree::ini_parser中的几个
  3    函数,用来操纵ini配置文件。ini文件用于比较简单的程序配置,因此该类被写成了单例。
  4    在C++11下,该类是线程安全的,否则不是。
  5    Note: 由于该类只和STL及boost打交道,因此使用了STL命名规范。注意property_tree会抛出异常,
  6    这里需要捕获异常,并返回错误码。
  7 */
  8 /************************************************************************/
  9 #ifndef CTI_SDK_USING_MFC_INI_PARSER_H
 10 #define CTI_SDK_USING_MFC_INI_PARSER_H
 11 
 12 #include <string>
 13 #include <map>
 14 #include <memory>
 15 #include <boost/property_tree/ptree.hpp>
 16 #include <boost/property_tree/ini_parser.hpp>
 17 //模板实现所需
 18 #include <boost/property_tree/exceptions.hpp>
 19 #include <boost/lexical_cast.hpp>
 20 
 21 class CIniParser :
 22     private boost::noncopyable
 23 {
 24 public:
 25     enum IniErrNo
 26     {
 27         kNoErr=0,
 28         kNotFound=1,
 29         kNotModified=2,
 30         kCanNotCreateFile=3,
 31         kOtherErr=10
 32     };
 33     static CIniParser& GetInstance(                         //获得单例
 34             const std::wstring& full_filename=L"config.ini");//文件的相对/绝对路径+文件名
 35 
 36     ~CIniParser(void){}
 37     template<typename T>
 38     int Get(const std::wstring& section_name,const std::wstring& property_name,
 39         T *result)const;
 40     template<typename T>
 41     int Put(const std::wstring& section_name,const std::wstring& property_name,
 42         const T& value);
 43     int PutMaps(const std::wstring& section_name,
 44         const std::map<std::wstring,std::wstring>& property_value_map);
 45 //#ifdef _MFC_VER
 46 //    //为方便使用,提供CString接口
 47     template<typename T>
 48     int Get(const CString& secitonName,const CString& propertyName,
 49         T* result)const;
 50     //CString非标准,lexical_cast会失败,因此需要特化
 51     template<>
 52     int Get<CString>(const CString& secitonName,const CString& propertyName,
 53         CString* result)const;
 54     template<typename T>
 55     int Put(const CString& sectionName,const CString& propertyName,
 56         const T& value);
 57     template<>
 58     int Put<CString>(const CString& sectionName,const CString& propertyName, 
 59         const CString& value);
 60     int PutMaps(const CString& sectionName,
 61         const std::map<CString,CString>& propertyValueMap);
 62 //#endif //!_MFC_VER
 63     
 64 private:
 65     CIniParser(const std::wstring& full_filename);
 66     std::string filename_;
 67     boost::property_tree::wptree pt_;
 68 };
 69 
 70 //模板函数的实现,由于VS不支持export关键字,模板函数只能定义在头文件中(考虑写在另一个文件,然后include)
 71 
 72 template<typename T>
 73 int CIniParser::Get(const std::wstring& section_name,
 74                     const std::wstring& property_name, 
 75                     T *result)const
 76 {
 77     std::wstring node(section_name+L"."+property_name);
 78     try
 79     {
 80         *result=pt_.get<T>(node);
 81     }catch(boost::property_tree::ptree_bad_data& e)
 82     {
 83         std::cout<<e.data<std::string>()<<std::endl;
 84         return CIniParser::kNotFound;
 85     }catch(boost::property_tree::ptree_bad_path& e)
 86     {
 87         std::cout<<e.what()<<std::endl;
 88         return CIniParser::kCanNotCreateFile;
 89     }
 90     catch(...)
 91     {
 92         return CIniParser::kOtherErr;
 93     }
 94     return 0;
 95 }
 96 
 97 template<typename T>
 98 int CIniParser::Get(const CString& secitonName,
 99                     const CString& propertyName,
100                     T *result)const
101 {
102     return Get(wstring(secitonName.GetString()),propertyName.GetString(),result);
103 }
104 
105 template<>
106 int CIniParser::Get<CString>(const CString& secitonName,const CString& propertyName,
107                              CString* result)const
108 {
109     std::wstring temp;
110     int err=Get(std::wstring(secitonName.GetString()),
111         propertyName.GetString(),
112         &temp);
113     *result=temp.c_str();
114     return err;
115 }
116 template<typename T>
117 int CIniParser::Put(const std::wstring& section_name,
118                     const std::wstring& property_name,
119                     const T& value)
120 {
121     std::wstring node(section_name+L"."+property_name);
122     int err=0;
123     try
124     {
125         pt_.put(node,value);
126         write_ini(filename_,pt_);
127     }
128     catch(boost::property_tree::ptree_bad_data& e)
129     {
130         err=CIniParser::kNotModified;
131         std::wcout<<e.data<std::wstring>()<<std::endl;
132     }
133     catch(boost::property_tree::ini_parser_error& e)
134     {
135         err=CIniParser::kNotModified;
136         std::cout<<"Line "<<e.line()
137             <<", file name: "<<e.filename()
138             <<", message: "<<e.message()
139             <<std::endl;
140     }
141     catch(...)
142     {
143         return CIniParser::kOtherErr;
144     }
145     return err;
146 }
147 template<typename T>
148 int CIniParser::Put(const CString& sectionName,const CString& propertyName,
149                     const T& value)
150 {
151     return Put(wstring(sectionName.GetString()),propertyName.GetString(),value);
152 }
153 
154 template<>
155 int CIniParser::Put<CString>(const CString& sectionName,const CString& propertyName, 
156                              const CString& value)
157 {
158     //指定实例函数
159     return Put(std::wstring(sectionName.GetString())
160         ,propertyName.GetString(),value.GetString());
161 }
162 
163 #endif // !CTI_SDK_USING_MFC_INI_PASER_H

实现文件:

 1 #include "IniParser.h"
 2 #include <fstream>
 3 #include <boost/property_tree/exceptions.hpp>
 4 #include <boost/lexical_cast.hpp>
 5 #include "tools.h"
 6 using namespace std;
 7 using namespace boost::property_tree;
 8 using namespace boost;
 9 
10 //Warn: 这种方法在C++11前是行不通的!可以使用boost::call_once完成
11 CIniParser& CIniParser::GetInstance(const std::wstring& full_filename)
12 {
13     static CIniParser instance(full_filename);
14     return instance;
15 }
16 
17 
18 int CIniParser::PutMaps(const std::wstring& section_name, 
19                         const std::map<std::wstring,std::wstring>& property_value_map)
20 {
21     int err=0;
22     for(auto pairs:property_value_map)
23     {
24         try
25         {
26             pt_.put(section_name+L"."+pairs.first,pairs.second);
27         }
28         catch(ptree_bad_data& e)
29         {
30             err=CIniParser::kNotModified;
31             wcout<<L"write error:"<<e.data<wstring>()<<endl;
32         }
33     }
34     try
35     {
36         write_ini(filename_,pt_);
37     }
38     catch(ini_parser_error& e)
39     {
40         err=CIniParser::kNotModified;
41         cout<<"Line "<<e.line()
42             <<", file name: "<<e.filename()
43             <<", message: "<<e.message()
44             <<endl;
45     }
46         return err;
47 }
48 
49 int CIniParser::PutMaps( const CString& sectionName,
50                         const std::map<CString,CString>& propertyValueMap )
51 {
52     map<wstring,wstring> temp_map;
53     for(auto pairs:propertyValueMap)
54     {
55         temp_map[pairs.first.GetString()]=pairs.second.GetString();
56     }
57     return PutMaps(sectionName.GetString(),temp_map);
58 }
59 
60 CIniParser::CIniParser( const std::wstring& full_filename)
61 {
62     wstring_to_string(full_filename,&filename_);
63     wfstream file(filename_,ios::in);
64     if (!file)
65     {
66         file.clear();
67         file.open(filename_,ios::out);
68         //这里可能抛出异常
69         assert(file);
70         file.close();
71     }
72     read_ini(filename_,pt_);
73 }

使用的工具函数:

 1 /************************************************************************/
 2 /* Instruction: 本文件主要包含了一些自己常用的工具函数,方便其他函数引用
 3 */
 4 /************************************************************************/
 5 #ifndef CTI_SDK_USING_MFC_TOOLS_H 
 6 #define CTI_SDK_USING_MFC_TOOLS_H
 7 #include <string>
 8 //UNICODE转换辅助函数
 9 //仅供内部使用
10 static int ANSIToUnicode(const char *src,int srcCount,wchar_t *dest,int destCount);
11 static int UnicodeToANSI(const wchar_t *src,int srcCount,char *dest,int destCount);
12 //for MFC only
13 #if defined(_MFC_VER)
14 int CStringAToCStringW(const CStringA& src,CStringW *dest);
15 int CStringWToCStringA(const CStringW& src,CStringA *dest);
16 CString GetIPFromDWORD(const DWORD& dw);
17 DWORD MakeIPToDWORD(const CString& ip);
18 #endif
19 //只涉及标准库,使用STL命名约定
20 int string_to_wstring(const std::string& src,std::wstring *dest);
21 int wstring_to_string(const std::wstring& src,std::string *dest);
22 
23 int GetUniqueName(const TCHAR *prefix,TCHAR *out,int outCount);
24 #endif // !CTI_SDK_USING_MFC_TOOLS_H 

实现:

  1 #include "tools.h"
  2 #include <boost/lexical_cast.hpp>
  3 
  4 using namespace std;
  5 using namespace boost;
  6 
  7 int ANSIToUnicode(const char *src,int srcCount,wchar_t *dest,int destCount)
  8 {
  9     assert(src && dest);
 10     assert(destCount >= srcCount);
 11 #ifdef WIN32
 12 #include <stringapiset.h>
 13     int err=MultiByteToWideChar(CP_ACP,0,src,-1,dest,destCount*sizeof(dest[0]));
 14     if (err==0)
 15     {
 16         err=static_cast<int>(GetLastError());
 17     }
 18     else
 19     {
 20         err=0;
 21     }
 22     return err;
 23 #else
 24     setlocale(LC_ALL,"");
 25     int err=mbstowcs(dest,src,destCount*sizeof(dest[0]));
 26     setlocale(LC_ALL,"C");
 27     return err;
 28 #endif // WIN32
 29 }
 30 int UnicodeToANSI(const wchar_t *src,int srcCount,char *dest,int destCount)
 31 {
 32     assert(src && dest);
 33     assert(destCount >= srcCount);
 34 #ifdef WIN32
 35     int err=WideCharToMultiByte(CP_ACP,0,src,-1,dest,destCount,NULL,NULL);
 36     if (err==0)
 37     {
 38         err=static_cast<int>(GetLastError());
 39     }
 40     else
 41     {
 42         err=0;
 43     }
 44     return err;
 45 #else
 46     setlocale(LC_ALL,"");
 47     int err=wcstombs(dest,src,destCount);
 48     setlocale(LC_ALL,"C");
 49     return err;
 50 #endif
 51 }
 52 int CStringAToCStringW(const CStringA& src,CStringW *dest)
 53 {
 54     int length;
 55 #ifdef WIN32
 56     length=MultiByteToWideChar(CP_ACP,0,src,-1,NULL,0)+1;
 57 #else
 58     length=mbstowcs(NULL,src,0)+1;
 59 #endif // WIN32
 60     wchar_t *destbuffer=new wchar_t[length];
 61     int err=ANSIToUnicode(src,src.GetLength(),destbuffer,length);
 62     dest->Format(L"%s",destbuffer);
 63     delete[] destbuffer;
 64     return err;
 65 }
 66 int CStringWToCStringA(const CStringW& src,CStringA *dest)
 67 {
 68     int length;
 69 #ifdef WIN32
 70     length=WideCharToMultiByte(CP_ACP,0,src,-1,NULL,0,NULL,NULL)+1;
 71 #else
 72     length=wcstombs(NULL,src,0)*2+1;
 73 #endif // WIN32
 74     char *destbuffer=new char[length];
 75     int err=UnicodeToANSI(src,src.GetLength(),destbuffer,length);
 76     dest->Format("%s",destbuffer);
 77     delete[] destbuffer;
 78     return err;
 79 }
 80 //TODO: 应该先实现标准的,再使用非标准的调用标准,这里懒得修改了
 81 int string_to_wstring(const string& src,wstring *dest)
 82 {
 83    CStringW destbuffer;
 84    int err=CStringAToCStringW(src.c_str(),&destbuffer);
 85    dest->assign(destbuffer.GetString());
 86    destbuffer.ReleaseBuffer();
 87    return err;
 88 }
 89 int wstring_to_string(const wstring& src,string *dest)
 90 {
 91     CStringA destbuffer;
 92     int err=CStringWToCStringA(src.c_str(),&destbuffer);
 93     dest->assign(destbuffer.GetString());
 94     destbuffer.ReleaseBuffer();
 95     return err;
 96 }
 97 
 98 //TODO: 完善错误处理
 99 int GetUniqueName(const TCHAR *prefix,TCHAR *out,int outCount)
100 {
101     int errcode=0;
102     TCHAR tszTemplate[MAX_PATH]={0};
103     errcode=_tcscat_s(tszTemplate,MAX_PATH*sizeof(TCHAR),_T("XXXXXX"));
104     assert(outCount >= _countof(tszTemplate));
105     errcode=_tmktemp_s(tszTemplate);
106     errcode=_tcscpy_s(out,outCount*sizeof(TCHAR),tszTemplate);
107     return errcode;
108 }
109 
110 CString GetIPFromDWORD( const DWORD& dw )
111 {
112     WORD hw=HIWORD(dw);
113     WORD lw=LOWORD(dw);
114     BYTE ip1stSection=HIBYTE(hw);
115     BYTE ip2ndSection=LOBYTE(hw);
116     BYTE ip3rdSection=HIBYTE(lw);
117     BYTE ip4thSection=LOBYTE(lw);
118     CString result;
119     result.Format(_T("%d.%d.%d.%d"),ip1stSection,ip2ndSection,ip3rdSection,
120         ip4thSection);
121     return result;
122 }
123 
124 DWORD MakeIPToDWORD( const CString& ip )
125 {
126     CString ipSections[4];
127     CString temp;
128     int pos=0,i=0;
129     temp=ip.Tokenize(_T("."),pos);
130     while (temp!=_T(""))
131     {
132         VERIFY(i<4);
133         ipSections[i++]=temp;
134         temp=ip.Tokenize(_T("."),pos);
135     }
136     BYTE ip1stSection=_ttoi(ipSections[0].GetString());
137     BYTE ip2ndSection=_ttoi(ipSections[1].GetString());
138     BYTE ip3rdSection=_ttoi(ipSections[2].GetString());
139     BYTE ip4thSection=_ttoi(ipSections[3].GetString());
140     //注意高低位顺序
141     WORD hw=MAKEWORD(ip2ndSection,ip1stSection);
142     WORD lw=MAKEWORD(ip4thSection,ip3rdSection);
143     DWORD result=MAKELONG(lw,hw);
144 
145     return result;
146 }

这几天写MFC程序,感觉最麻烦的就是unicode和ansi的转换。

C++最令人的讨厌的特性之一就是不缺省支持unicode,最讨厌的特性之二是没有好的GUI框架。

如果可以的话,还是直接用Qt最简单。C++的哲学确实偏向学院派,不管是ace,boost还是poco,甚至stl,单独拿出来学习,感觉都很惊艳,

但是在工业项目中间使用,就感觉各种别扭……

posted @ 2013-05-04 22:45  生无所息  阅读(1136)  评论(0编辑  收藏  举报