/************************************************************************ 函數功能: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);
}
} 數據庫