虽然微软早已经建议在WINDOWS中用注册表代替INI文件,但是在实际应用中,INI文件仍然有用武之地,尤其现在绿色软件的流行,越来越多的程序将自己的一些配置信息保存到了INI文件中。

INI文件是文本文件,由若干节(section)组成,在每个带括号的标题下面,是若干个关键词(key)及其对应的值(Value)

[Section]

Key=Value


VC中提供了API函数进行INI文件的读写操作,但是微软推出的C#编程语言中却没有相应的方法,下面我介绍一个读写INI文件的C#类并利用该类保存窗体的坐标,当程序再次运行的时候,窗体将显示在上次退出时的位置。


INIFILE类:

using System;

using System.IO;

using System.Runtime.InteropServices;

//因为我们需要调用API函数,所以必须创建System.Runtime.InteropServices 命名空间以提供可用于访问 .NET 中的 COM 对象和本机 API 的类的集合。

using System.Text;

namespace Ini



{

public class IniFile


{

public string path; //INI文件名

[DllImport("kernel32")]

private static extern long WritePrivateProfileString(string section,string key,string val,string filePath);

[DllImport("kernel32")]

private static extern int GetPrivateProfileString(string section,string key,string def,StringBuilder retVal,int size,string filePath);

//声明读写INI文件的API函数


public IniFile(string INIPath)


{

path = INIPath;

}

//类的构造函数,传递INI文件名

public void IniWriteValue(string Section,string Key,string Value)


{

WritePrivateProfileString(Section,Key,Value,this.path);

}

//写INI文件


public string IniReadValue(string Section,string Key)


{

StringBuilder temp = new StringBuilder(255);

int i = GetPrivateProfileString(Section,Key,"",temp,255,this.path);

return temp.ToString();

}

//读取INI文件指定

}

}


调用INIFILE类:

新建一个标准的C# WINDOWS应用程序项目,在窗体中分别增加命名为sect、key、val的三个文本框。

增加如下代码:

using Ini; //创建命名空间

//当窗体关闭时保存窗体坐标

private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)


{

IniFile ini = new IniFile("C://test.ini");

ini.IniWriteValue("LOC" ,"x" ,this.Location.X.ToString() );

ini.IniWriteValue("LOC " ,"y" ,this.Location.Y.ToString() );

//ToString方法将数字转换为字符串

}

//当窗体启动时,读取INI文件的值并赋值给窗体

private void Form1_Load(object sender, System.EventArgs e)


{

IniFile ini = new IniFile("C://test.ini");

Point p=new Point() ;

if ((ini.IniReadValue ("LOC" ,"x" )!="" ) && (ini.IniReadValue ("LOC" ,"y" )!=""))

//判断返回值,避免第一次运行时为空出错


{

p.X=int.Parse (ini.IniReadValue ("LOC" ,"x" ));

p.Y =int.Parse (ini.IniReadValue ("LOC" ,"y" ));

// int.Parse将字符串转换为int

this.Location =p;

}

}


另一个c++的类:
第一个文件是INIFILE.h

#include <algorithm>
#include <vector>

class KEY


{
public:
KEY(char* Source);
char Name[255];
char Value[255];
KEY();
virtual ~KEY();

};

class SECTION


{
public:
int count();
char Name[255];
char Value[255];
SECTION();
SECTION(char* Source);

virtual ~SECTION();
std::vector<KEY> Key;
};

class INIFILE


{
public:
void save();
KEY* GetKey(char *SecName, char* SecValue, char *KeyName);
SECTION* GetSec(char *SecName,char *SecValue);
void SetKey(char* SecName,char* SecValue,char* KeyName,char* KeyValue);
void SetSec(char* SecName,char* SecValue);
void Init(char* Source);
void Init();
int count();
KEY* GetKey(char* SecName,char* KeyName);
SECTION* GetSec(char* SecName);
INIFILE();
INIFILE(char* Source);
virtual ~INIFILE();

std::vector<SECTION> Section;

protected:
char IniFile[255];
};
第二个文件是INIFILE.cpp

#include "INIFILE.h"
#include <string>
#include <fstream.h>
#include <strstrea.h>



/**///////////////////////////////////////////////////////////////////////
// Construction/Destruction

/**///////////////////////////////////////////////////////////////////////
INIFILE::INIFILE()


{
memset(IniFile,0,255);
}

INIFILE::INIFILE(char* Source)


{
memset(IniFile,0,255);
strncpy(IniFile,Source,254);
}


INIFILE::~INIFILE()


{

}


/**///////////////////////////////////////////////////////////////////////
// SECTION Class

/**///////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Construction/Destruction

/**///////////////////////////////////////////////////////////////////////
SECTION::SECTION()


{
memset(Name,0,255);
memset(Value,0,255);
}

SECTION::SECTION(char* Source)


{
memset(Name,0,255);
memset(Value,0,255);

char Tmp[255]=
{0};
int i=0;
while(isspace(Source[i]))i++;
while(Source[i]=='[')i++;
char* pr=strstr(&Source[i],"]");
if(pr)
strncpy(Tmp,&Source[i],pr-&Source[i]);
else
strcpy(Tmp,&Source[i]);
char* ipos=strstr(Tmp,"=");

if(ipos)
{
int iName=ipos-Tmp;
strncpy(Name,Tmp,iName);
strcpy(Value,ipos+1);
}
else

{
strcpy(Name,Tmp);
}
}

SECTION::~SECTION()


{

}


/**///////////////////////////////////////////////////////////////////////
// KEY Class

/**///////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Construction/Destruction

/**///////////////////////////////////////////////////////////////////////
KEY::KEY()


{

}


KEY::~KEY()


{

}

SECTION* INIFILE::GetSec(char *SecName)


{
for(int i=0;i<Section.size();i++)
if(strstr(Section[i].Name,SecName))
return &Section[i];
return 0;
}



KEY* INIFILE::GetKey(char *SecName, char *KeyName)


{
SECTION* Sec=GetSec(SecName);
if(Sec!=0)

{
for(int i=0;i<Sec->count();i++)

{
if(strstr(Sec->Key[i].Name,KeyName))
return &Sec->Key[i];
}
}
return 0;
}


void INIFILE::Init()


{
ifstream F(IniFile);

if(F)
{

char buf[255]=
{0};

while(F.getline(buf,255))
{
int i=0;
while(isspace(buf[i]))i++;
if(&buf[i])

{
switch(buf[i])

{
case '[':

{
SECTION NewSec(&buf[i]);
Section.push_back(NewSec);
}
break;
default:

{
KEY NewKey(&buf[i]);
Section.back().Key.push_back(NewKey);
}
break;
}
}
memset(buf,0,255);
}
}
}


int INIFILE::count()
{
return Section.size();
}

void INIFILE::Init(char *Source)


{
memset(IniFile,0,255);
strncpy(IniFile,Source,254);
}

KEY::KEY(char *Source)


{
memset(Name,0,255);
memset(Value,0,255);

char Tmp[255]=
{0};
int i=0;
while(isspace(Source[i]))i++;
while(Source[i]=='[')i++;
char* pr=strstr(&Source[i],"]");
if(pr)
strncpy(Tmp,&Source[i],pr-&Source[i]);
else
strcpy(Tmp,&Source[i]);
char* ipos=strstr(Tmp,"=");

if(ipos)
{
int iName=ipos-Tmp;
strncpy(Name,Tmp,iName);
strcpy(Value,ipos+1);
}
else

{
strcpy(Name,Tmp);
}
}

int SECTION::count()


{
return Key.size();
}

void INIFILE::SetSec(char *SecName, char *SecValue)


{
int i=0;
while(isspace(SecName[i]))i++;
for(int j=0;j<Section[i].count();j++)
if((strstr(Section[i].Name,&SecName[i]))&&
(strstr(Section[i].Value,&SecValue[i])))
return;


{
SECTION NewSec;
strcpy(NewSec.Name,SecName);
strcpy(NewSec.Value,SecValue);
Section.push_back(NewSec);
}
}

void INIFILE::SetKey(char *SecName, char *SecValue, char *KeyName, char *KeyValue)


{
SetSec(SecName,SecValue);
SECTION* Sec=GetSec(SecName,SecValue);
if(Sec==0)return;
for(int i=0;i<Sec->count();i++)

{
if(strstr(Sec->Key[i].Name,KeyName))

{
strcpy(Sec->Key[i].Value,KeyValue);
return;
}
}

{
KEY NewKey;
strcpy(NewKey.Name,KeyName);
strcpy(NewKey.Value,KeyValue);
Sec->Key.push_back(NewKey);
}
}

SECTION* INIFILE::GetSec(char *SecName, char *SecValue)


{
for(int i=0;i<Section.size();i++)
if((strstr(Section[i].Name,SecName))&&(strstr(Section[i].Value,SecValue)))
return &Section[i];
return 0;
}

KEY* INIFILE::GetKey(char *SecName, char *SecValue, char *KeyName)


{
SECTION* Sec=GetSec(SecName,SecValue);
if(Sec!=0)

{
for(int i=0;i<Sec->count();i++)

{
if(strstr(Sec->Key[i].Name,KeyName))
return &Sec->Key[i];
}
}
return 0;
}

void INIFILE::save()


{
int i=0,j=0;
ofstream OutPut("E://3.ini");
for(i=0;i<this->count();i++)

{
OutPut << "[" << Section[i].Name;
if(strlen(Section[i].Value)>0)
OutPut << "=" << Section[i].Value;
OutPut << "]" << endl;
for(j=0;j<Section[i].count();j++)

{
OutPut << Section[i].Key[j].Name << "=" << Section[i].Key[j].Value << endl;
}
}
}

然后是main.cpp,相当于使用说明

//main.cpp

INIFILE X("E://1.ini");
X.Init();
KEY* Key=X.GetKey("USER","gzh","Note1");

if(Key!=0)
{
cout << Key->Name << endl;
cout << Key->Value << endl;
}

X.SetKey("USER","gzh","Note1","this is a test");
cout << endl;
Key=X.GetKey("USER","gzh","Note1");

if(Key!=0)
{
cout << Key->Name << endl;
cout << Key->Value << endl;
}

X.save();

X.Init("E://3.ini");
Key=X.GetKey("USER","gzh","Note1");

if(Key!=0)
{
cout << Key->Name << endl;
cout << Key->Value << endl;
}

INI文件编程
2003-11-3加入 来自未知 作者佚名 6条评论 点击16342次
在我们写的程序当中,总有一些配置信息需要保存下来,以便完成程序的功能,最简单的办法就是将这些信息写入INI文件中,程序初始化时再读入.具体应用如下:
一.将信息写入.INI文件中.
1.所用的WINAPI函数原型为:
BOOL WritePrivateProfileString(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpString,
LPCTSTR lpFileName
);
其中各参数的意义:
LPCTSTR lpAppName 是INI文件中的一个字段名.
LPCTSTR lpKeyName 是lpAppName下的一个键名,通俗讲就是变量名.
LPCTSTR lpString 是键值,也就是变量的值,不过必须为LPCTSTR型或CString型的.

LPCTSTR lpFileName 是完整的INI文件名.

2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入 c:/stud/student.ini 文件中.

CString strName,strTemp;
int nAge;
strName="张三";
nAge=12;
::WritePrivateProfileString("StudentInfo","Name",strName,"c://stud//student.ini");

此时c:/stud/student.ini文件中的内容如下:
[StudentInfo]

Name=张三
3.要将学生的年龄保存下来,只需将整型的值变为字符型即可:
strTemp.Format("%d",nAge);
::WritePrivateProfileString("StudentInfo","Age",strTemp,"c://stud//student.ini");

二.将信息从INI文件中读入程序中的变量.
1.所用的WINAPI函数原型为:
DWORD GetPrivateProfileString(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
LPCTSTR lpDefault,
LPTSTR lpReturnedString,
DWORD nSize,
LPCTSTR lpFileName
);
其中各参数的意义:
前二个参数与 WritePrivateProfileString中的意义一样.

lpDefault : 如果INI文件中没有前两个参数指定的字段名或键名,则将此值赋给变量.
lpReturnedString : 接收INI文件中的值的CString对象,即目的缓存器.
nSize : 目的缓存器的大小.
lpFileName : 是完整的INI文件名.
2.具体使用方法:现要将上一步中写入的学生的信息读入程序中.
CString strStudName;
int nStudAge;
GetPrivateProfileString("StudentInfo","Name","默认姓名",strStudName.GetBuffer(MAX_PATH),MAX_PATH,"c://stud//student.ini");
执行后 strStudName 的值为:"张三",若前两个参数有误,其值为:"默认姓名".

3.读入整型值要用另一个WINAPI函数:
UINT GetPrivateProfileInt(
LPCTSTR lpAppName,
LPCTSTR lpKeyName,
INT nDefault,
LPCTSTR lpFileName
);
这里的参数意义与上相同.使用方法如下:

nStudAge=GetPrivateProfileInt("StudentInfo","Age",10,"c://stud//student.ini");

三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下:
1.写入:
CString strTemp,strTempA;
int i;
int nCount=6;
file://共有6个文件名需要保存


for(i=0;i
{strTemp.Format("%d",i);
strTempA=文件名;
file://文件名可以从数组,列表框等处取得.
::WritePrivateProfileString("UseFileName","FileName"+strTemp,strTempA,"c://usefile//usefile.ini");
}
strTemp.Format("%d",nCount);
::WritePrivateProfileString("FileCount","Count",strTemp,"c://usefile//usefile.ini");
file://将文件总数写入,以便读出.

2.读出:
nCount=::GetPrivateProfileInt("FileCount","Count",0,"c://usefile//usefile.ini");

for(i=0;i
{strTemp.Format("%d",i);

strTemp="FileName"+strTemp;
::GetPrivateProfileString("CurrentIni",strTemp,"default.fil", strTempA.GetBuffer(MAX_PATH),MAX_PATH,"c://usefile//usefile.ini");

file://使用strTempA中的内容.
}

补充四点:

1.INI文件的路径必须完整,文件名前面的各级目录必须存在,否则写入不成功,该函数返回 FALSE 值.

2.文件名的路径中必须为 // ,因为在VC++中, // 才表示一个 / .

3.也可将INI文件放在程序所在目录,此时 lpFileName 参数为: ".//student.ini".

4.从网页中粘贴源代码时,最好先粘贴至记事本中,再往VC中粘贴,否则易造成编译错误,开始时我也十分不解,好好的代码怎么就不对呢?后来才找到这个方法.还有一些代码中使用了全角字符如:<,\等,也会
造成编译错误.

Windows中有GetPrivateProfileString 和WritePrivateProfileString函数可以进行读写INI配置文件,但这两个函数每取出一个数据,都要打开文件,在文件中进行搜索,这样处理的效率肯定会很慢,因此下面提供了一个将配置文件读入内存中的做法,这样做的好处是一次读取文件,快速搜索(使用Map映射)。可以将所有数据全部保存成字符串或者文件。

INI配置文件主要由四部分组成:组、键值、内容、注释和空行,下面给出一个例子文件进行说明

文件:E:/boot.ini


[boot loader] ;这里是一个组,下面的两行配置数据隶属于该组

timeout=1 ;这里在等号前面的是一个键值,等号后面的是一个内容

default=multi(0)disk(0)rdisk(0)partition(2)/WINNT;下面一行是一个空行


[operating systems];所有在';'后面的字符都属于注释,本程序不支持REM形式的注释

multi(0)disk(0)rdisk(0)partition(2)/WINNT="Microsoft Windows 2000 Professional" /fastdetect;sadfkl;

C:/="Microsoft Windows"


好了,知道了INI文件的结构,开始分析INI文件读入内存后应使用的数据结构。

一个INI文件可以看作是由一些组以及每个组下面的数据组成的,组是字符串形式的,而数据是一个比较复杂的对象。为了搜索的方便,所以这里采用了CMapStringToPtr来组织整个INI文件,这样的话可以由组的字符串方便地查询到该组中的数据

一个组下面的数据是由一些键值—à内容组成的映射关系,所以使用CMapStringToString来组这这些数据是最好不过的选择了。


下面给出这个类的头文件和实现部分。给出之前简单介绍该类的用法:

读取上述E:/boot.ini文件:



#include "cfgdata.h"


CCfgData CfgData;


//Load INI文件

CfgData.LoadCfgData("E://boot.ini");

CString str;

long l=0;

//设置当前组

CfgData.SetGroup("boot loader");

//读取long型数据到变量l

CfgData.GetLongData("timeout",l);

//读取字符串型数据到变量str

CfgData.GetStrData("default",str);

//设置当前组

CfgData.SetGroup("operating systems");

//读取字符串型数据到变量str

CfgData.GetStrData("multi(0)disk(0)rdisk(0)partition(2)//WINNT",str);

//读取字符串型数据到变量str

CfgData.GetStrData("C://",str);

//将整个配置数据保存进入字符串中

CfgData.SaveToStr(&str);

//将整个配置数据保存进入文件中,注意配置数据相互之间没有顺序关系,

//所以可能组和组之间、一个组的几个键值--->内容配对之间的顺序将会

//和以前不一致,另外所有的注释和空行丢失

CfgData.SaveCfgData("E://boot2.ini");

读者可以点击这里获得源代码,注意解压后将boot.ini拷贝到E:/,以便程序运行找到文件)

头文件CfgData.h

// CfgData.h: interface for the CCfgData class.
//

/**///////////////////////////////////////////////////////////////////////
#if !defined(AFX_CFGDATA_H__A40CDB9A_0E44_49E6_A460_505D76BA6414__INCLUDED_)
#define AFX_CFGDATA_H__A40CDB9A_0E44_49E6_A460_505D76BA6414__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class CCfgData


{
protected:
//组到配置数据的映射
CMapStringToPtr m_StrMapMap;
//当前组
CString m_strGroup;
public:
//构造配置数据
CCfgData();
//析构配置数据
virtual ~CCfgData();
//从文件加载配置数据

/**//*
参数: LPCTSTR strFileName 加载文件的名称
返回值:无
*/
void LoadCfgData(LPCTSTR strFileName);
//将配置数据保存到文件

/**//*
参数: LPCTSTR strFileName 保存文件的名称
返回值:成功返回TRUE 失败返回FALSE
*/
BOOL SaveCfgData(LPCTSTR strFileName);
//将配置数据保存到字符串

/**//*
参数: CString* pstr 要保存的字符串指针
返回值:成功返回TRUE 失败返回FALSE
*/
BOOL SaveToStr(CString* pstr);
//设置当前读取的组

/**//*
参数: 当前组名称
返回值:无
*/
void SetGroup(LPCTSTR strGroup);
//修改或者添加一条当前组中的数据

/**//*
参数: LPCTSTR strKey 要修改的数据的键值
LPCTSTR strValue要修改的数据的内容
返回值:
备注: 如果当前组在配置数据中存在,则修改或者添加该组对应键值的数据,如果当前组灾配置数据中不存在,则先创建该组
*/
BOOL SetData(LPCTSTR strKey,LPCTSTR strValue);
//得到当前组中对应键值中字符串类型的数据

/**//*
参数: LPCTSTR strKey 要得到的数据的键值
LPCTSTR strValue要得到的数据的内容
返回值:找到数据返回TRUE,否则返回FALSE
*/
virtual BOOL GetStrData(LPCTSTR strKey,CString &strValue);
//得到long型的数据

/**//*
参数: LPCTSTR strKey 要得到的数据的键值
long lValue 要得到的数据的值
返回值:找到数据返回TRUE,否则返回FALSE
*/
virtual BOOL GetLongData(LPCTSTR strKey,long &lValue);

protected:
//释放配置数据所占用的内存

/**//*
参数: 无
返回值:无
*/
void RemoveAll();
};

#endif // !defined(AFX_CFGDATA_H__A40CDB9A_0E44_49E6_A460_505D76BA6414__INCLUDED_)


源文件CfgData.cpp

// CfgData.cpp: implementation of the CCfgData class.
//

/**///////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CfgData.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


/**///////////////////////////////////////////////////////////////////////
// Construction/Destruction

/**///////////////////////////////////////////////////////////////////////
//构造配置数据

CCfgData::CCfgData()


{
//初始化配置数据
m_strGroup="设置";
}
//析构配置数据

CCfgData::~CCfgData()


{
RemoveAll();
}
//释放配置数据所占用的内存

/**//*
参数: 无
返回值:无
*/
void CCfgData::RemoveAll()


{
POSITION pos=m_StrMapMap.GetStartPosition();
while(pos)

{
CMapStringToString* pStrMap;
CString str;
m_StrMapMap.GetNextAssoc(pos,str,(void*&)pStrMap);
if(pStrMap!=NULL)

{
pStrMap->RemoveAll();
//删除掉CString--> 指针映射中的指针
delete pStrMap;
}
}
m_StrMapMap.RemoveAll();
}
//从文件加载配置数据

/**//*
参数: LPCTSTR strFileName 加载文件的名称
返回值:无
*/
void CCfgData::LoadCfgData(LPCTSTR strFileName)


{
int iReadLen=0;
CString str[3];
int iState=0;//0:正在读入键值 1:正在读入内容 2:正在读入组
unsigned char ch; //正在读取的字符
//清空配置数据
RemoveAll();
CFile file;
file.Open(strFileName, CFile::modeRead);
file.Seek(0,CFile::begin);
str[0]="";//存放键值字符串
str[1]="";//存放内容字符串
str[2]="";//存放组字符串
//字符串到字符串的映射,保存键值和内容
CMapStringToString* pStrMap=NULL;
do

{
iReadLen=file.Read(&ch,1);
if(iReadLen!=0)

{
//处理中文
if(ch>0x80)//中文

{
str[iState]+=ch;
iReadLen=file.Read(&ch,1);
if(iReadLen!=0)

{
str[iState]+=ch;
}
}else

{
switch(ch)

{
//处理'['读入组字符串
case '[':
str[0].TrimLeft();
str[0].TrimRight();
str[1].TrimLeft();
str[1].TrimRight();
//确认键值和内容数据为空,否则可能是键值和内容中的符号
if(str[0]==""&&str[1]=="")

{
pStrMap=NULL;
iState=2;
str[2]="";
}else

{
str[iState]+=ch;
}
break;
//处理']'组字符串读入完毕
case ']':
//确认读入的是组的字符串数据
str[2].TrimLeft();
str[2].TrimRight();
if(iState==2&&str[2]!="")

{
iState=0;
//新建一个组下的键值-->内容映射,放入该组
pStrMap=new CMapStringToString;
m_StrMapMap.SetAt(str[2],pStrMap);
}else

{
str[iState]+=ch;
}
break;
case '=':
//开始读入内容
iState=1;
str[1]="";
break;
//处理回车和注释
case ';':
case 0x0d:
case 0x0a:
iState=0;
//键值非空
str[0].TrimLeft();
str[0].TrimRight();
str[1].TrimLeft();
str[1].TrimRight();
if(str[0]!=""&&pStrMap!=NULL)

{
pStrMap->SetAt((LPCTSTR)str[0],(LPCTSTR)str[1]);
}
//处理完清空数据
str[0]="";
str[1]="";
//注释的话继续读入直到文件结束或者碰到回车符号
if(ch==';')

{
while((iReadLen=file.Read(&ch,1))>0)

{
//如果遇到回车符号,终止,并且将当前位置退回
if(ch==0x0d||ch==0x0a)

{
file.Seek(-1,CFile::current);
break;
}
}
}
break;
default:
//普通字符,添加进入相应位置
str[iState]+=ch;
break;
}
}
}
}while(iReadLen!=0);
file.Close();
}
//设置当前读取的组

/**//*
参数: 当前组名称
返回值:无
*/

void CCfgData::SetGroup(LPCTSTR strGroup)


{
m_strGroup=strGroup;
}
//得到当前组中对应键值中字符串类型的数据

/**//*
参数: LPCTSTR strKey 要得到的数据的键值
LPCTSTR strValue要得到的数据的内容
返回值:找到数据返回TRUE,否则返回FALSE
*/

BOOL CCfgData::GetStrData(LPCTSTR strKey, CString &strValue)


{
CMapStringToString* pStrMap=NULL;
//寻找当前组
if(m_StrMapMap.Lookup(m_strGroup,(void*&)pStrMap))

{
if(pStrMap->Lookup(strKey,strValue))
return TRUE;
return FALSE;
}
return FALSE;
}
//得到long型的数据

/**//*
参数: LPCTSTR strKey 要得到的数据的键值
long lValue 要得到的数据的值
返回值:找到数据返回TRUE,否则返回FALSE
*/
BOOL CCfgData::GetLongData(LPCTSTR strKey, long &lValue)


{
CString str;
//得到对应的字符串数据
if(CCfgData::GetStrData(strKey, str))

{
lValue=atoi((LPCTSTR)str);
return TRUE;
}
return FALSE;
}
//修改或者添加一条当前组中的数据

/**//*
参数: LPCTSTR strKey 要修改的数据的键值
LPCTSTR strValue要修改的数据的内容
返回值:
备注: 如果当前组在配置数据中存在,则修改或者添加该组对应键值的数据,如果当前组灾配置数据中不存在,则先创建该组
*/

BOOL CCfgData::SetData(LPCTSTR strKey, LPCTSTR strValue)


{
CMapStringToString* pStrMap=NULL;
//如果存在该组,直接加入或者修改
if(m_StrMapMap.Lookup(m_strGroup,(void*&)pStrMap))

{
pStrMap->SetAt(strKey,strValue);
return TRUE;
}else

{
//创建该组
pStrMap=new CMapStringToString;
m_StrMapMap.SetAt(m_strGroup,pStrMap);
pStrMap->SetAt(strKey,strValue);
return TRUE;
}
}
//将配置数据保存到文件

/**//*
参数: LPCTSTR strFileName 保存文件的名称
返回值:成功返回TRUE 失败返回FALSE
*/

BOOL CCfgData::SaveCfgData(LPCTSTR strFileName)


{
CFile file;
if(!file.Open(strFileName,CFile::modeCreate|CFile::modeWrite))
return FALSE;
POSITION pos=m_StrMapMap.GetStartPosition();
char ch[6]="[]/r/n=";//特殊符号
CString str[3];
while(pos)

{
CMapStringToString* pStrMap;
m_StrMapMap.GetNextAssoc(pos,str[2],(void*&)pStrMap);
if(pStrMap!=NULL)

{
//写入组
file.Write(&ch[0],1);
file.Write((LPSTR)(LPCTSTR)str[2],str[2].GetLength());
file.Write(&ch[1],1);
file.Write(&ch[2],2);
POSITION pos1=pStrMap->GetStartPosition();
while(pos1)

{
//写入键值和内容
pStrMap->GetNextAssoc(pos1,str[0],str[1]);
file.Write((LPSTR)(LPCTSTR)str[0],str[0].GetLength());
file.Write(&ch[4],1);
file.Write((LPSTR)(LPCTSTR)str[1],str[1].GetLength());
file.Write(&ch[2],2);
}
}
}
file.Close();
return TRUE;
}
//将配置数据保存到字符串

/**//*
参数: CString* pstr 要保存的字符串指针
返回值:成功返回TRUE 失败返回FALSE
备注: 程序流程和上面基本相同,不同的保存进入字符串中
*/

BOOL CCfgData::SaveToStr(CString *pstr)


{
if(pstr==NULL)return FALSE;
*pstr="";
POSITION pos=m_StrMapMap.GetStartPosition();
CString str[4];
while(pos)

{
CMapStringToString* pStrMap;
m_StrMapMap.GetNextAssoc(pos,str[2],(void*&)pStrMap);
if(pStrMap!=NULL)

{
str[3]=*pstr;
pstr->Format("%s[%s]/r/n",str[3],str[2]);
POSITION pos1=pStrMap->GetStartPosition();
while(pos1)

{
pStrMap->GetNextAssoc(pos1,str[0],str[1]);
str[3]=*pstr;
pstr->Format("%s%s=%s/r/n",str[3],str[0],str[1]);
}
}
}
return TRUE;
}