文档章节

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

IMGTN
 IMGTN
发布于 2012/12/01 17:06
字数 1456
阅读 5653
收藏 6

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);
}
}


© 著作权归作者所有

下一篇: VC 屏蔽warning
IMGTN
粉丝 24
博文 271
码字总数 240775
作品 0
珠海
私信 提问
Visual C++ 2005 利用ini文件生成Tree Control

Visual C++ 2005 利用ini文件生成Tree Control 作者:邵盛松 2009-05-10 下面是读取在ini文件形成TreeControl的实现 CString strPath; CString strConfig; TCHAR exeFullPath[MAX_PATH]; ::G......

晨曦之光
2012/05/23
103
0
MiniINI 0.4 发布

MiniINI 是一个用来解析 INI/CFG 配置文件的C++库,主要特点是可移植性、性能和小体积。支持上千种 INI 格式配置,易用简单。 该版本增加了 STL API,使得 MiniINI 可在 STL 类中使用;增加配...

小编辑
2010/02/01
178
0
C++笔记(一)20110223

近日,公司准备用C++来做个类似openmeetings的软件。C++只是在学校时学习了,当当购了三本《Visal C++ 入门经典(第五版)》、《深入浅出MFC》、《Visaual C++ 音频你/视频处理技术及工程实践...

钟小华
2011/02/23
423
0
CodeForce-1196D2-RGB Substring (hard version)

原题链接 题目大意与上题完全一样,只是数据规模更大。 思路: 再用上题的暴力肯定TLE,所以需要优化一下搜索过程。上一题我们是外层遍历n,内层遍历3种情况。这题我们外层遍历3种情况,内层...

李义山
2019/07/28
0
0
Visual Studio 2012 Build Clang

不知道还有没有人记得Borland C/C++,C/C++四国圣战中的主角,换了老板 如今还在不冷不热的发展 ,支持Win32/Win64 OSX平台,即Embarcadero C++ Builder 现在支持Windows 64编程 最近试了一下...

Force武装卫队
2013/01/14
11.1K
24

没有更多内容

加载失败,请刷新页面

加载更多

如何使用Selenium WebDriver截屏

有谁知道是否可以使用Selenium WebDriver截屏? (注:不是硒RC) #1楼 吉顿 import org.openqa.selenium.OutputType as OutputTypeimport org.apache.commons.io.FileUtils as FileUtils......

技术盛宴
29分钟前
4
0
高阶函数

定义:能够包装函数的,使原本函数增加一些额外的福利的函数 比如: function higherOrderFn(fn){} 能够对fn增加一些额外的福利 应用场景: (function () { var getLogin = functio...

gtandsn
35分钟前
9
0
架构师成长之后

小致Daddy
37分钟前
6
0
Git 介绍和日常命令

git 介绍 GitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为唯一的版本库格式进行托管,故名GitHub。 GitHub于2008年4月10日正式上线,除了Git代码仓库托管及基本的 Web管理...

郭靖Michael
今天
9
0
技巧以管理R会话中的可用内存

人们使用什么技巧来管理交互式R会话的可用内存? 我使用下面的函数(基于Petr Pikal和David Hinds在2004年r-help列表中的发布)列出(和/或排序)最大的对象,并偶尔对其中一些对象进行rm() ...

javail
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部