轻松实现一个操作ini文件的类
作者:lixiaosan(CSDN)
前言:
相信很多朋友在编写自己的程序中,都需要把一些数据先期导入到程序中进行初始化。那么这个时候,比较好的做法就是把你所有的数据写入一个ini文件,然后在程序去读ini文件中的数据对行初始化。
一.INI简介
那么什么是ini文件呢?ini文件是Initialization file的缩写,意即初始化文件。(从名字就可以看出它的功能了吧)。不仅你自己的程序可以使用ini文件,其实windows操作系统也有自己的ini文件---win.ini,保存在%WinDir%"system32目录下。Windows通过该文件对当前操作系统进行配置。
ini文件里的数据的存取是采取的是预先约定好的 “项-值”存储结构,各种数据被分门别类的存储。以下是win.ini 文件的部分内容。
[Mail] MAPI=1 CMC=1 CMCDLLNAME=mapi.dll CMCDLLNAME32=mapi32.dll MAPIX=1 MAPIXVER=1.0.0.1 OLEMessaging=1 |
通过以上内容,我们可以看到,ini文件将各种数据分成很多以“[ ]”组成的节,而在每一个“节”中又包含了很多“项”,“项”后面紧跟着一个等号,等号后面则是该项的值。在该例中[Mail]就是一个“节”,MAPI是一个项,1则是MAPI的值。
所以,它的通用形式我们可以总结成:
[Section]
Key=KeyValue
二.操作ini文件的API
windows SDK提供有两组API对ini文件进行读写。
读 |
写 |
GetPrivateProfileString GetPrivateProfileInt |
WritePrivateProfileString |
GetPrivateProfileSection |
WritePrivateProfileSection |
GetPrivateProfileSectionNames |
|
GetPrivateProfileStruct |
WritePrivateProfileStruct |
表2
读 |
写 |
GetProfileString GetProfileInt |
WriteProfileString |
GetProfileSection |
WritePrivateProfileSection |
表3
对用户的配置文件来说,一般我们使用的是表2中的函数,这一点从函数中的“private”就可以看出它是针对私有的配置文件的函数(又是废话!)。而表3中的函数则是提供给针对系统配置文件,即win.ini进行操作的函数。现只准备介绍表2中的函数,这也是使用率最高的,表3中的函数操作和表2中的函数操作类同,故略。
现在我们来看看这几个函数的功能:
DWORD GetPrivateProfileString(
LPCTSTR lpAppName, //节名,即Section
LPCTSTR lpKeyName, //项名,即Key
LPCTSTR lpDefault, //缺省返回字符串。如lpKeyName未找到,拷贝lpDefault到lpReturnedString
LPTSTR lpReturnedString, //返回字符串的缓冲地址
DWORD nSize, //缓冲大小
LPCTSTR lpFileName //ini文件路径
);
功能:根据指定的Section和 Key得到KeyValue,存放在lpReturnedString中
返回:返回拷贝到缓冲中的字符个数。不包括结束符
UINT GetPrivateProfileInt(
LPCTSTR lpAppName, //节名,即Section
LPCTSTR lpKeyName, //项名,即Key
INT nDefault, //缺省返回整型值。如lpKeyName未找到,函数返回nDefault的值
LPCTSTR lpFileName //ini文件路径
);
功能:根据指定的Section和 Key得到整型KeyValue
返回:返回得到的整型KeyValue
BOOL WritePrivateProfileString(
LPCTSTR lpAppName, //节名,即Section
LPCTSTR lpKeyName, //项名,即Key
LPCTSTR lpString, //要写入的字符串
LPCTSTR lpFileName //ini文件路径
);
功能:向指定的Section和 Key写入KeyValue。
如果lpString为NULL,则删除当前lpKeyName
如果lpKeyName=lpString=NULL,则删除当前Section以及其下的所有Key
如果Section或者Key不存在,则创建;存在则覆盖
返回:写入成功。
DWORD GetPrivateProfileSectionNames(
LPTSTR lpszReturnBuffer, //存放所有Section的缓冲地址
DWORD nSize, //缓冲大小
LPCTSTR lpFileName //ini文件路径
);
功能:得到ini文件中所有Section名。
返回:返回拷贝到缓冲中的字符个数。不包括结束符。
注意:返回的所有Section在缓冲中的存放格式为“Section1”,0,“Section2”,0。。。。
若需要得到具体的每个Section,则需要进行字符串解析。在后面的IniFile类中的GetAllKeysAndValues函数中会看到解
析步骤。
DWORD GetPrivateProfileSection(
LPCTSTR lpAppName, //节名,即Section
LPTSTR lpReturnedString, //存放指定Section下所有的Key和KeyValue的缓冲地址
DWORD nSize, //缓冲大小
LPCTSTR lpFileName //ini文件路径
);
功能:得到指定Section下所有的Key和KeyValue。
返回:返回拷贝到缓冲中的字符个数。不包括结束符。
注意:返回的“项-值对”在缓冲中的存放格式为“Key1=KeyValue1”,0,“Key2=KeyValue2”,0 。。。。
若需要得到具体的Key和KeyValue,则需要进行字符串解析。在后面的IniFile类中的GetAllKeysAndValues函数中会看到解析步骤。
GetPrivateProfileStruct和WritePrivateProfileStruct用的较少,本文也未介绍,感兴趣的朋友可以自己看看MSDN,里面也有详细介绍。
三.一个ini的类
有了以上的API后,我们就可以轻松的制作一个简单的操作ini文件的类了。
//////////////////////////////////////////////////////////////////////////
// File: IniFile.h
// Date: October 2004
// Author: lixiaosan
// Email: airforcetwo@163.com
// Copyright (c) 2004. All Rights Reserved.
//////////////////////////////////////////////////////////////////////////
#if !defined(AFX_INIFILE_H__B5C0D7F7_8353_4C93_AAA4_38A688CA253C__INCLUDED_)
#define AFX_INIFILE_H__B5C0D7F7_8353_4C93_AAA4_38A688CA253C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
classCIniFile
{
public:
CIniFile();
virtual ~CIniFile();
// 设置ini文件路径
// 成功返回TRUE;否则返回FALSE
BOOL SetPath(CStringstrPath);
// 检查section是否存在
// 存在返回TRUE;否则返回FALSE
BOOL SectionExist(CStringstrSection);
// 从指定的Section和Key读取KeyValue
// 返回KeyValue
CString GetKeyValue(CString strSection,
CString strKey);
// 设置Section、Key以及KeyValue,若Section或者Key不存在则创建
void SetKeyValue(CString strSection,
CString strKey,
CString strKeyValue);
// 删除指定Section下的一个Key
void DeleteKey(CStringstrSection,
CStringstrKey);
// 删除指定的Section以及其下的所有Key
void DeleteSection(CStringstrSection);
// 获得所有的Section
// 返回Section数目
int GetAllSections(CStringArray& strArrSection);
// 根据指定Section得到其下的所有Key和KeyValue
// 返回Key的数目
int GetAllKeysAndValues(CStringstrSection,
CStringArray& strArrKey,
CStringArray& strArrKeyValue);
// 删除所有Section
void DeleteAllSections();
private:
// ini文件路径
CStringm_strPath;
};
#endif // !defined(AFX_INIFILE_H__B5C0D7F7_8353_4C93_AAA4_38A688CA253C__INCLUDED_)
//////////////////////////////////////////////////////////////////////////
// File: IniFile.cpp
// Date: October 2004
// Author: lixiaosan
// Email: airforcetwo@163.com
// Copyright (c) 2004. All Rights Reserved.
//////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
//#include "test6.h"
#include "IniFile.h"
#ifdef _DEBUG
#undef THIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#define newDEBUG_NEW
#endif
#define MAX_SECTION 260 //Section最大长度
#define MAX_KEY 260 //KeyValues最大长度
#define MAX_ALLSECTIONS 65535 //所有Section的最大长度
#define MAX_ALLKEYS 65535 //所有KeyValue的最大长度
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CIniFile::CIniFile()
{
}
CIniFile::~CIniFile()
{
}
//////////////////////////////////////////////////////////////////////////
// Public Functions
//////////////////////////////////////////////////////////////////////////
BOOLCIniFile::SetPath(CStringstrPath)
{
m_strPath = strPath;
// 检查文件是否存在
DWORD dwFlag = GetFileAttributes((LPCTSTR)m_strPath);
// 文件或者路径不存在,返回FALSE
if( 0xFFFFFFFF == dwFlag )
returnFALSE;
// 路径是目录,返回FALSE
if ( FILE_ATTRIBUTE_DIRECTORY & dwFlag )
returnFALSE;
returnTRUE;
}
BOOLCIniFile::SectionExist(CStringstrSection)
{
TCHARchSection[MAX_SECTION];
DWORDdwRetValue;
dwRetValue = GetPrivateProfileString(
(LPCTSTR)strSection,
NULL,
_T(""),
chSection,
sizeof(chSection)/sizeof(TCHAR),
(LPCTSTR)m_strPath);
return (dwRetValue>0);
}
CStringCIniFile::GetKeyValue(CStringstrSection,
CStringstrKey)
{
TCHAR chKey[MAX_KEY];
DWORD dwRetValue;
CStringstrKeyValue=_T("");
dwRetValue = GetPrivateProfileString(
(LPCTSTR)strSection,
(LPCTSTR)strKey,
_T(""),
chKey,
sizeof(chKey)/sizeof(TCHAR),
(LPCTSTR)m_strPath);
strKeyValue = chKey;
returnstrKeyValue;
}
voidCIniFile::SetKeyValue(CStringstrSection,
CStringstrKey,
CStringstrKeyValue)
{
WritePrivateProfileString(
(LPCTSTR)strSection,
(LPCTSTR)strKey,
(LPCTSTR)strKeyValue,
(LPCTSTR)m_strPath);
}
voidCIniFile::DeleteKey(CStringstrSection, CStringstrKey)
{
WritePrivateProfileString(
(LPCTSTR)strSection,
(LPCTSTR)strKey,
NULL, // 这里写NULL,则删除Key
(LPCTSTR)m_strPath);
}
voidCIniFile::DeleteSection(CStringstrSection)
{
WritePrivateProfileString(
(LPCTSTR)strSection,
NULL,
NULL, // 这里都写NULL,则删除Section
(LPCTSTR)m_strPath);
}
intCIniFile::GetAllSections(CStringArray& strArrSection)
{
intdwRetValue, i, j, iPos=0;
TCHARchAllSections[MAX_ALLSECTIONS];
TCHARchTempSection[MAX_SECTION];
ZeroMemory(chAllSections, MAX_ALLSECTIONS);
ZeroMemory(chTempSection, MAX_SECTION);
dwRetValue = GetPrivateProfileSectionNames(
chAllSections,
MAX_ALLSECTIONS,
m_strPath);
// 因为Section在数组中的存放形式为“Section1”,0,“Section2”,0,0。
// 所以如果检测到连续两个0,则break
for(i=0; i<MAX_ALLSECTIONS; i++)
{
if( chAllSections[i] == NULL )
{
if( chAllSections[i] == chAllSections[i+1] )
break;
}
}
i++; // 保证数据读完
strArrSection.RemoveAll();// 清空数组
for(j=0; j<i; j++)
{
chTempSection[iPos++] = chAllSections[j];
if( chAllSections[j] == NULL )
{
strArrSection.Add(chTempSection);
ZeroMemory(chTempSection, MAX_SECTION);
iPos = 0;
}
}
returnstrArrSection.GetSize();
}
intCIniFile::GetAllKeysAndValues(CString strSection,
CStringArray& strArrKey,
CStringArray& strArrKeyValue)
{
intdwRetValue, i, j, iPos=0;
TCHARchAllKeysAndValues[MAX_ALLKEYS];
TCHARchTempkeyAndValue[MAX_KEY];
CStringstrTempKey;
ZeroMemory(chAllKeysAndValues, MAX_ALLKEYS);
ZeroMemory(chTempkeyAndValue, MAX_KEY);
dwRetValue = GetPrivateProfileSection(
strSection,
chAllKeysAndValues,
MAX_ALLKEYS,
m_strPath);
// 因为Section在数组中的存放形式为“Key1=KeyValue1”,0,“Key2=KeyValue2”,0
// 所以如果检测到连续两个0,则break
for(i=0; i<MAX_ALLSECTIONS; i++)
{
if( chAllKeysAndValues[i] == NULL )
{
if( chAllKeysAndValues[i] == chAllKeysAndValues[i+1] )
break;
}
}
i++;
strArrKey.RemoveAll();
strArrKeyValue.RemoveAll();
for(j=0; j<i; j++)
{
chTempkeyAndValue[iPos++] = chAllKeysAndValues[j];
if( chAllKeysAndValues[j] == NULL )
{
strTempKey = chTempkeyAndValue;
strArrKey.Add( strTempKey.Left(strTempKey.Find('=')) );
strArrKeyValue.Add( strTempKey.Mid(strTempKey.Find('=')+1) );
ZeroMemory(chTempkeyAndValue, MAX_KEY);
iPos = 0;
}
}
returnstrArrKey.GetSize();
}
voidCIniFile::DeleteAllSections()
{
intnSecNum;
CStringArraystrArrSection;
nSecNum = GetAllSections(strArrSection);
for(inti=0; i<nSecNum; i++)
{
WritePrivateProfileString(
(LPCTSTR)strArrSection[i],
NULL,
NULL,
(LPCTSTR)m_strPath);
}
}
四.例子
比如在存在一个myfile.ini文件,内容如下:
[student]
number=40
male=25
female=15
average_age=15
[computer]
cpu=2.0
motherboard=ASUS
harddisk=120
ram=512
display=sansung
现在把IniFile.h和IniFile.cpp 加入到你的工程中。在使用他的类中#include “IniFile.h”;
CIniFilefile;
CStringArrayarrSection, arrKey, arrkeyValue;
file.SetPath("f:""myfile.ini");
CStringstr="";
if(file.SectionExist("student"))
{
//str="15"
str = file.GetKeyValue("student", "female");
//设置number为50
file.SetKeyValue("student", "number", "50");
//因为在student中computer_num不存在,所以增加一项
file.SetKeyValue("student", "computer_num", "30");
//得到所有section
intnum = file.GetAllSections(arrSection);
str = "";
for(inti=0; i<num; i++)
{
str += arrSection[i] + " ";//str="student computer ";
}
//得到所有Key和KeyValue
intnum = file.GetAllKeysAndValues("computer", arrKey, arrkeyValue);
str = "";
for(intj=0; j<num; j++)
{
//arrKey保存了computer下所有的Key
//arrkeyValue保存了computer下所有的KeyValue
str = arrKey[j];
str = arrkeyValue[j];
}
//删除student下的computer_num
file.DeleteKey("student", "computer_num");
//删除student
file.DeleteSection("student");
}
有兴趣的朋友,可以在该类基础上进行扩展,添加你自己喜欢的功能。比如说返回int而不是字符串。
就讲到这里吧,欢迎大家指正。:)
更多技术文章请参看施昌权的个人网站: http://www.joyvc.cn