Wince读取ini的CIniParse类

//========================================================================
//TITLE:
// Wince读取ini的CIniParse类
//AUTHOR:
// norains
//DATE:
// Monday 22-December-2008
//Environment:
// WINCE5.0 + VS2005 + ARM BSP
//========================================================================

挺奇怪的是,微软在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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值