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);
}
} 數據庫

相關文章
相關標籤/搜索