现在位置:首页 >> 嵌入式操作系统 >> Windows CE
WinCE 读取ini的CIniParse类
作者:phantom 时间:2009/8/14 文章来源:来自网络

    挺奇怪的是,微软在wince中没有像桌面系统般有读取ini的特定函数。为了解决该问题,网上有不少牛人都给给出了相应的解决方案,比如说:
   
    benkaoya的直接C++/C代码读写:http://blog.csdn.net/benkaoya/archive/2008/01/28/2070648.aspx
   
    xumercury的将以上函数封装为类:http://blog.csdn.net/xumercury/archive/2008/07/09/2629346.aspx
   
    khan的STL读写类:http://www.cppblog.com/Khan/archive/2007/08/09/29459.html?opt=admin
   
    不过,以上的这几个都有一些小问题,或是效率较低,或是有一些小bug,其实最引起自己重写冲动的是因为命名规则和自己的理念有冲突,所以索性就自己另起炉灶弄了个CIniParse。因为习惯问题,我的代码基本上充斥的是STL代码,如果不喜欢这风格,可以使用benkaoya或xumercury的作品,他们的这个代码也是比较成熟的;关于khan的LIniFile类,在他blog的留言中,似乎公布的这个类代码是有缺陷的,完整的代码需要发信向其索取。因为我没有他的完整版代码,所以我也不做更多的评论。
   
    写完这段有损人利己嫌疑的言语后,我们来看看今天的主角:CIniParse。之前说了别人的代码的缺陷,现在也该说说CIniParse所存在的一些问题了。可能最让人不爽的是,CIniParse类在保存的时候,会将原来的注释全部清除掉,并且原来的顺序也全部重排。如果注释以及顺序对你非常重要,请勿使用CIniParse类。
   
    除此以外,该类并不能在ASCII环境中编译通过。只是wince是UNICODE的系统,所以这点在平时使用中倒不会引起很大的麻烦。当然,如果你是打算移植到VC6.0中,那么可能有一些函数就必须要修正了。再一点就是,该类没有详细地进行测试,所以应该还会有或多或少的问题,如果你发现了,也希望我更正,期待你的指出。
   
    惯例,先罗列出CIniParse的完整代码:
   
    头文件:

 

//Class Name
// CIniParse
//
//Version:
// 1.0.0
//
//Date:
// 2008.12.22
//
//Author:
// norains
//////////////////////////////////////////////////////////////////////

#pragma once

#include "windows.h"
#include <string>
#include <vector>
#include <map>

#ifdef UNICODE
 #ifndef TSTRING
  #define TSTRING std::wstring
 #endif
#else
 #ifndef TSTRING
  #define TSTRING std::string
 #endif
#endif


class CIniParse
{
public:
 //-------------------------------------------------------------------------------
 //Description:
 // Open the ini file.
 //-------------------------------------------------------------------------------
 BOOL Open(TSTRING strFile);

 //-------------------------------------------------------------------------------
 //Description:
 // Get the profile value as string type
 //-------------------------------------------------------------------------------
 TSTRING GetPrivateProfileString(const TSTRING &strSection,const TSTRING &strKey);

 //-------------------------------------------------------------------------------
 //Description:
 // Get the profile value as int type
 //-------------------------------------------------------------------------------
 int GetPrivateProfileInt(const TSTRING &strSection,const TSTRING &strKey);

 //-------------------------------------------------------------------------------
 //Description:
 // Set the profile value as string type.The function wouldn't save the data to file
 //but memory. If you want to save to the file, you must call Flush function
 //-------------------------------------------------------------------------------
 BOOL SetPrivateProfileString(const TSTRING &strSection,const TSTRING &strKey,TSTRING strSet);

 //-------------------------------------------------------------------------------
 //Description:
 // Set the profile value as int type.The function wouldn't save the data to file
 //but memory. If you want to save to the file, you must call Flush function
 //-------------------------------------------------------------------------------
 BOOL SetPrivateProfileInt(const TSTRING &strSection,const TSTRING &strKey,int iSet);

 //-------------------------------------------------------------------------------
 //Description:
 // Flush the memory buffer to the file
 //-------------------------------------------------------------------------------
 BOOL Flush();

public:
 CIniParse();
 virtual ~CIniParse();


private:
 //-------------------------------------------------------------------------------
 //Description:
 // Get the line value base on the current offset. After calling, the offset value
 //would move to the head of next line
 //-------------------------------------------------------------------------------
 TSTRING GetLine();

 //-------------------------------------------------------------------------------
 //Description:
 // Check the string value of one line whether is comment or not
 //-------------------------------------------------------------------------------
 static BOOL IsCommentLine(const TSTRING & strLine);

 //-------------------------------------------------------------------------------
 //Description:
 // Check the string value of one line whether is the section.
 //Parameters:
 // strLine : [in] The string value buffer.
 //-------------------------------------------------------------------------------
 static BOOL IsSectionLine(const TSTRING & strLine);


 //-------------------------------------------------------------------------------
 //Description:
 // Get the key value from one line
 //Parameters:
 // strLine : [in] The buffer to find
 //-------------------------------------------------------------------------------
 static TSTRING GetKeyValueFromLine(const TSTRING & strLine);


 //-------------------------------------------------------------------------------
 //Description:
 // Get the key name from one line
 //Parameters:
 // strLine : [in] The buffer to find
 //-------------------------------------------------------------------------------
 static TSTRING GetKeyNameFromLine(const TSTRING & strLine);

 //-------------------------------------------------------------------------------
 //Description:
 // Get the section name from one line
 //Parameters:
 // strLine : [in] The buffer to find
 //-------------------------------------------------------------------------------
 static TSTRING GetSectionNameFromLine(const TSTRING & strLine);

 //-------------------------------------------------------------------------------
 //Description:
 // Remove the space from the string
 //Parameters:
 // strBuf : [in] The buffer to remove
 //Return Value:
 // Return the string without space
 //-------------------------------------------------------------------------------
 static TSTRING RemoveSpace(const TSTRING &strBuf);


 //-------------------------------------------------------------------------------
 //Description:
 // Parse the ini file
 //-------------------------------------------------------------------------------
 void Parse(const TSTRING &strBuf);

 //-------------------------------------------------------------------------------
 //Description:
 // Convert the string to  lowercase
 //-------------------------------------------------------------------------------
 static TSTRING ConvertToLowercase(const TSTRING &strBuf);

 //-------------------------------------------------------------------------------
 //Description:
 // Reset the offset point to the begin
 //-------------------------------------------------------------------------------
 BOOL ResetOffset();

 //-------------------------------------------------------------------------------
 //Description:
 // Check whether the offset arrived the end of the buffer.
 //-------------------------------------------------------------------------------
 BOOL IsOffsetEnd();


private:
 TSTRING m_strFileBuf;
 TSTRING::size_type m_stOffset;
 TSTRING m_strFilePath;
 std::map<TSTRING, std::map<TSTRING,TSTRING> > m_mpValue; //The first TSTRING is section name, the second is key name and last is the value.
};

    

   

 

实现体:
 

   #include "IniParse.h"
#include <deque>
#include <algorithm>

 

CIniParse::CIniParse():
m_stOffset(0)
{}

CIniParse::~CIniParse()
{}

BOOL CIniParse::Open(TSTRING strFile)
{
 HANDLE hFile = CreateFile(strFile.c_str(),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
 if(hFile == INVALID_HANDLE_VALUE)
 {
  return FALSE;
 }

 m_strFilePath = strFile;

 DWORD dwSize = GetFileSize(hFile,NULL);

 //Read the file to buffer
 std::vector<BYTE> vtBuf(dwSize,0);
 DWORD dwRead = 0;
 ReadFile(hFile,&vtBuf[0],vtBuf.size(),&dwRead,NULL);
 vtBuf.resize(dwRead);

 CloseHandle(hFile);

 #ifdef UNICODE

  m_strFileBuf.clear();

  if(vtBuf.size() >= 2)
  {
   if(vtBuf[0] == 0xFF && vtBuf[1] == 0xFE)
   {
    //Unicode file

    //Convert the read buffer to the unicode.The TCHAR here is equal to wchar_t
    std::deque<TCHAR> dqBuf;
    for(std::vector<BYTE>::size_type i = 2; i < vtBuf.size(); i += 2)
    {
     dqBuf.push_back(vtBuf[i] + (vtBuf[i+1] << 8));
    }

    
    m_strFileBuf.insert(m_strFileBuf.end(),dqBuf.begin(),dqBuf.end());
   }
   else
   {
    std::vector<TCHAR> vtBufT;
    vtBufT.resize(MultiByteToWideChar (CP_ACP, 0, reinterpret_cast<char *>(&vtBuf[0]), vtBuf.size(), NULL, 0));
    MultiByteToWideChar (CP_ACP, 0, reinterpret_cast<char *>(&vtBuf[0]), vtBuf.size(), &vtBufT[0], vtBufT.size());  
   
    m_strFileBuf.insert(m_strFileBuf.end(),vtBufT.begin(),vtBufT.end());
   }
  }

 #else

  #error "Unfortunately! The source code donesn't complete in the ASCII environment"

 #endif

 


 Parse(m_strFileBuf);

 return TRUE;
}

TSTRING CIniParse::GetLine()
{
 TSTRING strReturn;

 if(m_stOffset >= m_strFileBuf.size())
 {
  return TSTRING();
 }

 TSTRING::size_type stPos = m_strFileBuf.find(TEXT("\r\n"),m_stOffset);
 if(stPos == TSTRING::npos)
 {
  strReturn.insert(0,m_strFileBuf,m_stOffset,m_strFileBuf.size() - m_stOffset + 1); 

  //Move the offset position to end of the file
  m_stOffset = m_strFileBuf.size() + 1;
 }
 else
 {
  strReturn.insert(0,m_strFileBuf,m_stOffset,stPos - m_stOffset); 

  //Move the offset position to the back of the "\r\n" 
  m_stOffset = stPos + 2;

 }

 return strReturn;
}

BOOL CIniParse::IsCommentLine(const TSTRING &strLine)
{
 if(strLine.empty() != FALSE || strLine[0] == ';')
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}

BOOL CIniParse::IsSectionLine(const TSTRING &strLine)
{
 TSTRING::size_type stLeft = strLine.find(TEXT("["));
 TSTRING::size_type stRight = strLine.find(TEXT("]"));
 if(strLine.empty() == FALSE && stLeft != TSTRING::npos && stRight != TSTRING::npos && stRight > stLeft)
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}

TSTRING CIniParse::GetKeyValueFromLine(const TSTRING &strLine)
{
 TSTRING::size_type stPosEqual = strLine.find(TEXT("="));
 if(stPosEqual == TSTRING::npos)
 {
  return TSTRING();
 }

 

 TSTRING strReturn;

 TSTRING::size_type stPosQuoteLeft = strLine.find(TEXT("\""),stPosEqual);
 if(stPosQuoteLeft != TSTRING::npos)
 {
  TSTRING::size_type stPosQuoteRight = strLine.find(TEXT("\""),stPosQuoteLeft + 1);
  if(stPosQuoteRight != TSTRING::npos && stPosQuoteLeft + 1 != stPosQuoteRight)
  {
   strReturn.insert(0,strLine,stPosQuoteLeft + 1,stPosQuoteRight - stPosQuoteLeft - 1);
   return strReturn;
  }
 }


 //Store the string to the buffer
 if(stPosEqual + 1 > strLine.size())
 {
  return TSTRING();
 }
 TSTRING strBuf(strLine,stPosEqual + 1,strLine.size() - stPosEqual);;
 return RemoveSpace(strBuf);
}


TSTRING CIniParse::GetKeyNameFromLine(const TSTRING &strLine)
{
 TSTRING::size_type stPosEqual = strLine.find(TEXT("="));
 if(stPosEqual == 0)
 {
  return TSTRING();
 }

 TSTRING strBuf;
 if(stPosEqual == TSTRING::npos)
 {
  //All of the string line is the key name
  strBuf = strLine;
 }
 else
 {
  strBuf.clear();
  strBuf.insert(0,strLine,0,stPosEqual);
 }

 return RemoveSpace(strBuf);

}

TSTRING CIniParse::GetSectionNameFromLine(const TSTRING &strLine)
{
 TSTRING::size_type stLeft = strLine.find(TEXT("["));
 TSTRING::size_type stRight = strLine.find(TEXT("]"));
 if(!(strLine.empty() == FALSE && stLeft != TSTRING::npos && stRight != TSTRING::npos && stRight > stLeft))
 {
  return TSTRING();
 }

 TSTRING strBuf(strLine,stLeft + 1,stRight - stLeft - 1); 
 return RemoveSpace(strBuf);

}

TSTRING CIniParse::RemoveSpace(const TSTRING &strBuf)
{
 if(strBuf.find(TEXT(" ")) != TSTRING::npos)
 {
  //Remove the space
  TSTRING strReturn;
  for(TSTRING::size_type stPos = 0; stPos < strBuf.size(); stPos ++)
  {
   if(strBuf[stPos] != ' ')
   {
    strReturn.push_back(strBuf[stPos]);
   }
  }
  return strReturn;
 }
 else
 {
  //No space
  return strBuf;
 }
}

void CIniParse::Parse(const TSTRING &strBuf)
{
 //Reset the file pointer to the begin
 ResetOffset();

 std::map<TSTRING,TSTRING> mpKey;
 TSTRING strSection;

 while(TRUE)
 {
  TSTRING strLine = GetLine();

  if(strLine.empty() != FALSE || IsCommentLine(strLine) != FALSE)
  {
   if(IsOffsetEnd())
   {
    break;
   }
   else
   {
    continue;
   }
  }

  if(IsSectionLine(strLine) != FALSE)
  {   
   if(strSection.empty() != FALSE)
   {
    //It's the first section

    strSection = GetSectionNameFromLine(strLine);
    continue;
   }

   //Store the last section value
   m_mpValue.insert(std::make_pair(strSection,mpKey));

   strSection = GetSectionNameFromLine(strLine);
   mpKey.clear();
  }
  else
  {
   if(strSection.empty() != FALSE)
   {
    //The section name is empty, so needn't store the key value
    continue;
   }

   //Store the key value and name
   TSTRING strKeyName = GetKeyNameFromLine(strLine);
   if(strKeyName.empty() == FALSE)
   {
    mpKey.insert(std::make_pair(strKeyName,GetKeyValueFromLine(strLine)));
   }
  }
 }

 //Store the last section value
 if(strSection.empty() == FALSE)
 {
  m_mpValue.insert(std::make_pair(strSection,mpKey));
 }
}


TSTRING CIniParse::ConvertToLowercase(const TSTRING &strBuf)
{
 std::vector<TCHAR> vtBuf(strBuf.length() + 1,0);
 _tcscpy(&vtBuf[0],strBuf.c_str());
 return _tcslwr(&vtBuf[0]);
}

BOOL CIniParse::ResetOffset()
{
 m_stOffset = 0;
 return TRUE;
}

BOOL CIniParse::IsOffsetEnd()
{
 if(m_stOffset >= m_strFileBuf.size())
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}

TSTRING CIniParse::GetPrivateProfileString(const TSTRING &strSection,const TSTRING &strKey)
{
 if(m_mpValue.empty() != FALSE)
 {
  return TSTRING();
 }

 //Ignoring the character case to find the specified key 
 for(std::map<TSTRING, std::map<TSTRING,TSTRING>>::iterator iterSection = m_mpValue.begin(); iterSection != m_mpValue.end(); iterSection ++)
 {
  if(ConvertToLowercase(iterSection->first) == ConvertToLowercase(strSection))
  {
   for(std::map<TSTRING,TSTRING>::iterator iterKey = iterSection->second.begin(); iterKey != iterSection->second.end(); iterKey ++)
   {
    if(ConvertToLowercase(iterKey->first) == ConvertToLowercase(strKey))
    {
     return iterKey->second;
    }
   }
  }
 }

 return TSTRING();
}

int CIniParse::GetPrivateProfileInt(const TSTRING &strSection,const TSTRING &strKey)
{
 return _ttoi(GetPrivateProfileString(strSection,strKey).c_str());
}

BOOL CIniParse::SetPrivateProfileString(const TSTRING &strSection,const TSTRING &strKey,TSTRING strSet)
{


 //Ignoring the character case to find the specified key 
 for(std::map<TSTRING, std::map<TSTRING,TSTRING>>::iterator iterSection = m_mpValue.begin(); iterSection != m_mpValue.end(); iterSection ++)
 {
  if(ConvertToLowercase(iterSection->first) == ConvertToLowercase(strSection))
  {
   for(std::map<TSTRING,TSTRING>::iterator iterKey = iterSection->second.begin(); iterKey != iterSection->second.end(); iterKey ++)
   {
    if(ConvertToLowercase(iterKey->first) == ConvertToLowercase(strKey))
    {
     iterKey->second = strSet;
     return TRUE;
    }
   }

   //Add the new key value
   iterSection->second.insert(std::make_pair(strKey,strSet));

   return TRUE;
  }
 }


 //Add the new section and key value
 std::map<TSTRING,TSTRING> mpKey;
 mpKey.insert(std::make_pair(strKey,strSet));
 m_mpValue.insert(std::make_pair(strSection,mpKey));

 return TRUE;
}

BOOL CIniParse::SetPrivateProfileInt(const TSTRING &strSection,const TSTRING &strKey,int iSet)
{
 std::vector<TCHAR> vtBuf(MAX_PATH,0);
 TSTRING strSet = _itot(iSet,&vtBuf[0],10);
 return SetPrivateProfileString(strSection,strKey,strSet);
}

BOOL CIniParse::Flush()
{
 TSTRING strWrite;
 //strWrite.reserve(m_mpValue.size());

 //Store the string value to the buffer
 for(std::map<TSTRING, std::map<TSTRING,TSTRING>>::iterator iterSection = m_mpValue.begin(); iterSection != m_mpValue.end(); iterSection ++)
 {
  strWrite += TEXT("\r\n[");
  strWrite += iterSection->first;
  strWrite += TEXT("]\r\n");

  for(std::map<TSTRING,TSTRING>::iterator iterKey = iterSection->second.begin(); iterKey != iterSection->second.end(); iterKey ++)
  {
   strWrite += iterKey->first;
   strWrite += TEXT("=");
   strWrite += iterKey->second;
   strWrite += TEXT("\r\n");
  }
 }


 //Write to the file
 HANDLE hFile = CreateFile(m_strFilePath.c_str(),GENERIC_WRITE,NULL,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
 if(INVALID_HANDLE_VALUE != hFile)
 {

  std::vector<BYTE> vtWrite;
  vtWrite.reserve(sizeof(TCHAR) * strWrite.size());
    
  #ifdef UNICODE
   vtWrite.push_back(0xFF);
   vtWrite.push_back(0xFE);
   for(TSTRING::iterator iter = strWrite.begin(); iter != strWrite.end(); iter++)
   {
    vtWrite.push_back(static_cast<BYTE>(*iter));
    vtWrite.push_back((*iter)>>8);
   }
  #else
   vtWrite.assign(strWrite.begin(),strWrite.end());
  #endif

  DWORD dwWrite = 0;
  WriteFile(hFile,&vtWrite[0],vtWrite.size(),&dwWrite,NULL);
  CloseHandle(hFile);

  return TRUE;
 }
 else
 {
  return FALSE;
 } 
}

    

具体使用如下:
 


   int WINAPI WinMain( HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     LPTSTR    lpCmdLine,
     int       nCmdShow)
{

 //声明一个对象
 CIniParse iniParse;

 //打开相应的ini文件
 iniParse.Open(TEXT("\\NAND\\test.ini"));

 TSTRING strValue ;
 int iValue = 0;

 //获取特定的SECTION和KEY的数值。可以有两种返回形式,一种是TSTRING,另一种是int。
 strValue = iniParse.GetPrivateProfileString(TEXT("VERSION_INI_FILE"),TEXT("VERSION_CONFIG_INFO")); 
 iValue = iniParse.GetPrivateProfileInt(TEXT("VERSION_INI_FILE"),TEXT("VERSION_CONFIG_INFO"));

 //更改相应KEY的数值
 iniParse.SetPrivateProfileString(TEXT("VERSION_INI_FILE"),TEXT("VERSION_CONFIG_INFO"),TEXT("5600")); 
 strValue = iniParse.GetPrivateProfileString(TEXT("VERSION_INI_FILE"),TEXT("VERSION_CONFIG_INFO")); 


 //增加新的SECTION和KEY数值
 iniParse.SetPrivateProfileString(TEXT("VERSION_INI_FILE_NEW"),TEXT("VERSION_CONFIG_INFO_NEW"),TEXT("98600")); 
 strValue = iniParse.GetPrivateProfileString(TEXT("VERSION_INI_FILE_NEW"),TEXT("VERSION_CONFIG_INFO_NEW")); 

 //写到文件中
 iniParse.Flush();

 return 0; 
}


    在这里还有一点需要注意的是,因为从效率考虑,SetPrivateProfileString函数更改的数值都只是在内存中做修改,如果需要保存到文件中,需要调用Flush函数。调用Flush函数后,内存的数据就保存到之前Open传入的文件路径中。
   
    如果想保存到C++动态数组中,也可以实现,只是有点麻烦:
   

 

  strValue = iniParse.GetPrivateProfileString(TEXT("VERSION_INI_FILE_NEW"),TEXT("VERSION_CONFIG_INFO_NEW"));  
 TCHAR *pNewBuf = new TCHAR[strValue.size() + 1];
 _tcscpy(pNewBuf,strValue.c_str());
 delete []pNewBuf;

 用动态数组还需要手动释放资源,相对来说,就不如直接用STL来得更为简便。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/norains/archive/2008/12/22/3584120.aspx


上一篇:Explorer注册表键值归纳[返回列表]下一篇: WinCE 的编程忠告