C++ Programmer's Cookbook

{C++ 基础} {C++ 高级} {C#界面,C++核心算法} {设计模式} {C#基础}

读取ini文件

虽然微软早已经建议在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;
 
}


其他的五个实例:
http://www.vckbase.com/code/listcode.asp?mclsid=15&sclsid=1509

posted on 2006-01-17 10:02 梦在天涯 阅读(8731) 评论(0)  编辑 收藏 引用 所属分类: CPlusPlusC#/.NET


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

EMail:itech001#126.com

导航

统计

  • 随笔 - 461
  • 文章 - 4
  • 评论 - 746
  • 引用 - 0

常用链接

随笔分类

随笔档案

收藏夹

Blogs

c#(csharp)

C++(cpp)

Enlish

Forums(bbs)

My self

Often go

Useful Webs

Xml/Uml/html

搜索

  •  

积分与排名

  • 积分 - 1785089
  • 排名 - 5

最新评论

阅读排行榜