Visual C++中巧妙遍历INI配置文件

Visual C++中巧妙遍历INI配置文件


  

/************************************************************************
函数功能:INI文件的遍历
函数参数:   1 pFilePath  ini文件的路径
           2 strKey     需要遍历的键值项
           3 map_Key    关联式容器map 返回该键值下的所有子项 
        
*/
/************************************************************************/
inline void EnumIniFile(LPCTSTR pFilePath, CString strKey,map<CString,int>& map_Key)
{
     
    // TODO: Add your control notification handler code here
    TCHAR strAppNameTemp[1024];//所有AppName的返回值
    TCHAR strKeyNameTemp[1024];//对应每个AppName的所有KeyName的返回值
    TCHAR strReturnTemp[1024];//返回值
    DWORD dwKeyNameSize;//对应每个AppName的所有KeyName的总长度
    //所有AppName的总长度
    DWORD dwAppNameSize = GetPrivateProfileString(NULL,NULL,NULL,strAppNameTemp,1024,pFilePath);
    if(dwAppNameSize>0)
    {
        TCHAR *pAppName = new TCHAR[dwAppNameSize];
        int nAppNameLen=0;  //每个AppName的长度
        for(int i = 0;i<dwAppNameSize;i++)
        {
            pAppName[nAppNameLen++]=strAppNameTemp[i];
            if(strAppNameTemp[i]=='')
            {
                OutputDebugString(pAppName);
                OutputDebugString(_T("/r/n"));
                dwKeyNameSize = GetPrivateProfileString(pAppName,NULL,NULL,strKeyNameTemp,1024,pFilePath);
 
                if (pAppName == strKey)//这里是我们要遍历的键值
                {
                    if(dwAppNameSize>0)
                    {
                        TCHAR *pKeyName = new TCHAR[dwKeyNameSize];
                        int nKeyNameLen=0;    //每个KeyName的长度
                        for(int j = 0;j<dwKeyNameSize;j++)
                        {
 
                            pKeyName[nKeyNameLen++]=strKeyNameTemp[j];
                            if(strKeyNameTemp[j]=='')
                            {
                                OutputDebugString(pKeyName);
                                OutputDebugString(_T("="));
                                if(GetPrivateProfileString(pAppName,pKeyName,NULL,strReturnTemp,1024,pFilePath))
                                    OutputDebugString(strReturnTemp);
 
                                CString strKeyName(pKeyName);
                                int     iTemp = atoi(strReturnTemp);
                                map_Key.insert(make_pair(strKeyName,iTemp));
 
                                memset(pKeyName,0,dwKeyNameSize);
                                nKeyNameLen=0;
                                OutputDebugString(_T("/r/n"));
                            }
                        }
                        delete[]pKeyName;
 
                    }
                }               
                 
                memset(pAppName,0,dwAppNameSize);
                nAppNameLen=0;
            }
        }
        delete[]pAppName;
    }   
}








    在基于Windows的软件项目的开发过程中,总是会涉及到配置信息的管理问题。保存配置信息的载体有多种,比如,可以选择数据库,或者XML文件。对于信息量很大且复杂的配置信息,使用数据库或XML来管理是可靠的。然而,对于信息量较小的配置信息,使用数据库或XML,未免有些“杀鸡用牛刀”了。那么,对于这些小信息量的配置信息,有没有更“经济”又“省力”的方法呢?
       INI原是Windows的系统配置信息文件,假如您的操作系统安装在C分区,那么,在C:\下有一个“BOOT.INI”文件,其中保存着操作系统的启动选项,此为INI文件应用的经典例子。同样,将INI在我们的程序设计之中,一样有妙用。
      遗憾的是,在INI的支持方面,Visual C++ 不像C++ Builder那样体贴。C++ Builder提供了TIniFile类,全面支持INI文件的读写操作,而Visual C++没有,只“扔”给了我们如下几个函数:
       GetPrivateProfileString:读取指定Section(节点)下的字串(值)
      GetPrivateProfileSectionNames:读取文件中的Section名称
      WritePrivateProfileString:将字串写入指定Section中
       这给我们遍历INI文件带来的困难。然而这并不能阻挡我们享受INI文件给我们带来的便利。本文将介绍我在工程中使用上述函数巧妙遍历INI文件的方法。
      假设我们的配置文件内容如下:
   [CAN卡01] ;Section(节点)
   01=探头名称1 ;01为关键字,“探头名称1”为值
   02=探头名称2 ;值2
   03=探头名称3 ;值3
   04=探头名称4 ;值4
   05=探头名称5 ;值5
   06=探头名称6 ;值6
   07=探头名称7 ;值7
   08=探头名称8 ;值8
   09=探头名称9 ;值9
   10=探头名称10 ;值10
   11=探头名称11 ;值11
         结合MSDN对这几个函数的介绍,很容易想到的是,使用GetPrivateProfileSectionNames函数获取节点名称,以此作为参数给GetPrivateProfileString函数,读取第一个关键字名称,接着再读取该关键字下的值。代码如下:
char strSection[128];
CString strFileName = _T(".\\UnitInfo.INI"); //INI文件路径
DWORD nChar = GetPrivateProfileSectionNames(strSection,sizeof(strSection),strFileName); //获取Section名称,保存在strSection中
nChar = GetPrivateProfileString(strSection,NULL,"",strBuffer,sizeof(strBuffer),strFileName); //读取第一个关键字名称,保存在strBuffer
strUnitID = strBuffer; //作为下一个调用的参数
nChar = GetPrivateProfileString(strSection,strUnitID,"",strBuffer,sizeof(strBuffer),strFileName); //读取关键字下的值
strUnitName = strBuffer;
       问题来了,当我们再想读取下一个值(上图中的“值2”)时,发现办不到了。因为当我们再次运用上述代码时,只能获取到第一个关键字以及该关键字下的值。解决的办法是,每当读完当前行后,将当前行删除,下一行将被置顶,再使用上述代码读取下一行,直到文件末尾,即nChar返回0。如何删除当前行呢?使用WritePrivateProfileString函数数,注意指定第三个参数为NULL,代码如下:
WritePrivateProfileString(strSection,strUnitID,NULL,strFileName);
细心的您可能会问,怎么可以将配置文件信息都删除了,如此一来,程序下一次运行岂不是读不到信息?别急,在我们读完所需要的所有配置信息后,我们必须重建该配置文件。如何重建?只需循环调用WritePrivateProfileString函数。代码如下:
WritePrivateProfileString(strSection,strUnitID,strUnitName,strFileName); //strSection、strUnitID、strUnitName为之前保存下来的值
在工程中,我将上述遍历过程写成函数,以便调用。为方便您理解,下面给出该函数的代码,并附上详细注释:
/读出配置文件中的探头信息/
void GetUnitINI()
{
extern CString g_UnitID[32]; //全局变量:探头编号
extern CString g_UnitName[32]; //全局变量:探头名称
extern int g_UnitNumber;   //全局变量:探头总数

char strBuffer[128];   //临时缓冲区,用于接收字符串
char strSection[128]; //用于接收节点名称
CString strFileName = _T(".\\UnitInfo.INI"); //INI文件位于VC++工程的根目录

//获取第一个节点名
DWORD nChar = GetPrivateProfileSectionNames(strSection,sizeof(strSection),strFileName);
for (int i = 0; i < g_UnitNumber; i++)
{
   //保存探头标识
   nChar = GetPrivateProfileString(strSection,NULL,"",strBuffer,sizeof(strBuffer),strFileName);
   g_UnitID[i] = strBuffer;
   //保存探头名称
   nChar = GetPrivateProfileString(strSection,g_UnitID[i],"",strBuffer,sizeof(strBuffer),strFileName);
   g_UnitName[i] = strBuffer;
   //将此探头从配置文件中删除
   WritePrivateProfileString(strSection,g_UnitID[i],NULL,strFileName);
   //读不到信息,表示已经遍历整个INI文件,则退出循环
   if (0 == nChar)
   {
    break;
   }
   //保存探头个数
   g_UnitNumber = i + 1;
}
//将探头信息重新写入配置文件
for(i = 0; i < g_UnitNumber; i++)
{
   WritePrivateProfileString(strSection,g_UnitID[i],g_UnitName[i],strFileName);
}
}


转载于:https://my.oschina.net/ypimgt/blog/93299

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值