自制的一个读写INI文件的类
- 格式:doc
- 大小:66.50 KB
- 文档页数:11
VB读写INI文件今天,我们将应用制作一个能够实现读写INI文件的应用程序。
程序运行结果如图所示。
运行结果技术要点●INI文件的格式●GetPrivateProfileInt()和GetPrivateProfileString()函数●WritePrivateProfileString()函数实现步骤■新建项目打开Visual ,选择“新建项目”,在项目类型窗口中选择“Visual Basic项目”,在模板窗口中,选择“Windows应用程序”,在名称域中输入“RWIni”,然后选择保存路径。
单击“确认”。
■添加控件和菜单向当前窗体上添加两个Button控件,用于控制读写INI文件;一个Group控件和两个RadioButton控件,用于控制读写整型数据还是字符串型;三个Label控件和三个TextBox 控件,用于标注和输入节名、键名和值;其余两个Label控件,一个表示当前打开的文件名,另一个表示读写的状态。
最后添加一个MainMenu控件,生成菜单“文件”、“退出”,其中“文件”下有一个子菜单“打开INI文件”。
■设置属性切换到“属性栏”,对窗体上的控件设置属性。
详细情况见下表。
窗体各控件的属性值知识点:一个INI文件由若干节(Section)组成,每个节中又由若干个关键字(Keyword)和值组成。
关键字是用来保存独立的程序设置和那些重要信息的,用于控制应用程序的某个功能;值可以是整型数或字符串。
如果值为空,则表示应用程序已经为该关键字指定了缺省值。
INI文件的一般形式如下:…………[Section]keyword=value…………INI文件有严格的格式要求:(1)节名必须加“[”和“]”。
(2)对文件做注释,要以“;”开头。
(3)关键字后必须有“=”。
■添加代码keywordinfo = txtkeyword.TextValueinfo = txtvalue.Text' 检查输入是否合法,不合法时,提示警告信息。
C语⾔读取写⼊ini配置⽂件的⽅法实现⽬录⼀、了解什么是INI⽂件?⼆、INI⽂件的格式三、解析上述⽂件四、测试如下⼀、了解什么是INI⽂件?ini ⽂件是Initialization File的缩写,即初始化⽂件,这是⽤来配置应⽤软件以实现不同⽤户的要求。
⼆、INI⽂件的格式INI⽂件由节、键、值组成。
⼀个简单的的INI⽂件例⼦如下:[Setting]INIT_FLAG=0;VOLUME=1;LANGUAGE=1;如上例⼦,[Setting]就是节,=号左边的值是键,=号右边的是值。
三、解析上述⽂件/*ini.h*/#ifndef INI_H#define INI_H#include <stdio.h>#include <string.h>int GetIniKeyString(char *title,char *key,char *filename,char *buf);int PutIniKeyString(char *title,char *key,char *val,char *filename);#endif /*INI_H*//*ini.c*/#include <stdio.h>#include <string.h>/** 函数名: GetIniKeyString* ⼊⼝参数: title* 配置⽂件中⼀组数据的标识* key* 这组数据中要读出的值的标识* filename* 要读取的⽂件路径* 返回值:找到需要查的值则返回正确结果 0* 否则返回-1*/int GetIniKeyString(char *title,char *key,char *filename,char *buf){FILE *fp;int flag = 0;char sTitle[64], *wTmp;char sLine[1024];sprintf(sTitle, "[%s]", title);if(NULL == (fp = fopen(filename, "r"))) {perror("fopen");return -1;}while (NULL != fgets(sLine, 1024, fp)) {// 这是注释⾏if (0 == strncmp("//", sLine, 2)) continue;if ('#' == sLine[0]) continue;wTmp = strchr(sLine, '=');if ((NULL != wTmp) && (1 == flag)) {if (0 == strncmp(key, sLine, strlen(key))) { // 长度依⽂件读取的为准sLine[strlen(sLine) - 1] = '\0';fclose(fp);while(*(wTmp + 1) == ' '){wTmp++;}strcpy(buf,wTmp + 1);return 0;}} else {if (0 == strncmp(sTitle, sLine, strlen(sTitle))) { // 长度依⽂件读取的为准flag = 1; // 找到标题位置}}}fclose(fp);return -1;}/** 函数名: PutIniKeyString* ⼊⼝参数: title* 配置⽂件中⼀组数据的标识* key* 这组数据中要读出的值的标识* val* 更改后的值* filename* 要读取的⽂件路径* 返回值:成功返回 0* 否则返回 -1*/int PutIniKeyString(char *title,char *key,char *val,char *filename){FILE *fpr, *fpw;int flag = 0;char sLine[1024], sTitle[32], *wTmp;sprintf(sTitle, "[%s]", title);if (NULL == (fpr = fopen(filename, "r")))return -1;// 读取原⽂件sprintf(sLine, "%s.tmp", filename);if (NULL == (fpw = fopen(sLine, "w")))return -1;// 写⼊临时⽂件while (NULL != fgets(sLine, 1024, fpr)) {if (2 != flag) { // 如果找到要修改的那⼀⾏,则不会执⾏内部的操作wTmp = strchr(sLine, '=');if ((NULL != wTmp) && (1 == flag)) {if (0 == strncmp(key, sLine, strlen(key))) { // 长度依⽂件读取的为准flag = 2;// 更改值,⽅便写⼊⽂件sprintf(wTmp + 1, " %s\n", val);}} else {if (0 == strncmp(sTitle, sLine, strlen(sTitle))) { // 长度依⽂件读取的为准flag = 1; // 找到标题位置}}}fputs(sLine, fpw); // 写⼊临时⽂件}fclose(fpr);fclose(fpw);sprintf(sLine, "%s.tmp", filename);return rename(sLine, filename);// 将临时⽂件更新到原⽂件}上述两个函数是简单的解析函数,因为ini⽂件有很多种解析⽅式,根据不同的需求解析也不同所以要进⾏修改⽐如我的注释符号是 “ ;”,所以我需要修改并且根据实际功能需求也可以进⾏进⼀步的封装四、测试如下ini样本⽂件/*test.ini*/[city]beijing = hello-beijingshanghai = hello-shanghai#information[study]highschool = xxxxuniversity = yyyytest.c程序/*test.c*/#include "ini.h"#include <stdio.h>int main(int argc, char const *argv[]){char buff[100];int ret;ret = GetIniKeyString("city","beijing","./test.ini",buff);printf("ret:%d,%s\n",ret,buff);ret = GetIniKeyString("study","highschool","./test.ini",buff);printf("ret:%d,%s\n",ret,buff);ret = PutIniKeyString("study","highschool","zzzz","./test.ini");printf("put ret:%d\n",ret);ret = GetIniKeyString("study","highschool","./test.ini",buff);printf("ret:%d,%s\n",ret,buff);return 0;}结果如下:ret:0,hello-beijingret:0,xxxxput ret:0ret:0,zzzz相应的test.ini的study段highschool项变成了zzzz.这⾥还要注意,section使⽤中⽂字符可能会⽆法识别!到此这篇关于C语⾔读取写⼊ini配置⽂件的⽅法实现的⽂章就介绍到这了,更多相关C语⾔读取写⼊ini 内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
在VC++中读写INI文件在VC++中读写INI文件在我们写的程序当中,总有一些配置信息需要保存下来,以便完成程序的功能,最简单的办法就是将这些信息写入INI文件中,程序初始化时再读入.具体应用如下:一.将信息写入.INI文件中.1.所用的WINAPI函数原型为:其中各参数的意义:LPCTSTR lpAppName 是INI文件中的一个字段名.LPCTSTR lpKeyName 是lpAppName下的一个键名,通俗讲就是变量名.LPCTSTR lpString 是键值,也就是变量的值,不过必须为LPCTSTR型或CString型的.LPCTSTR lpFileName 是完整的INI文件名.2.具体使用方法:设现有一名学生,需把他的姓名和年龄写入 c:\stud\student.ini 文件中.此时c:\stud\student.ini文件中的内容如下:[StudentInfo]Name=张三3.要将学生的年龄保存下来,只需将整型的值变为字符型即可:二.将信息从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.具体使用方法:现要将上一步中写入的学生的信息读入程序中.执行后 strStudName 的值为:"张三",若前两个参数有误,其值为:"默认姓名".3.读入整型值要用另一个WINAPI函数:UINT GetPrivateProfileInt(LPCTSTR lpAppName,LPCTSTR lpKeyName,INT nDefault,LPCTSTR lpFileName);这里的参数意义与上相同.使用方法如下:三.循环写入多个值,设现有一程序,要将最近使用的几个文件名保存下来,具体程序如下: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中粘贴,否则易造成编译错误,开始时我也十分不解,好好的代码怎么就不对呢?后来才找到这个方法.还有一些代码中使用了全角字符如:<,\等,也会造成编译错误.。
C语言读取INI配置文件Ini.h#pragma once#include"afxTempl.h"class DLLPORT CIni{private:CString m_strFileName;public:CIni(CString strFileName) :m_strFileName(strFileName){}public://一般性操作:BOOL SetFileName(LPCTSTR lpFileName); //设置文件名CString GetFileName(void); //获得文件名BOOL SetValue(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpValue, bool bCreate = true); //设置键值,bCreate是指段名及键名未存在时,是否创建。
CString GetValue(LPCTSTR lpSection, LPCTSTR lpKey); //得到键值.BOOL DelSection(LPCTSTR strSection); //删除段名BOOL DelKey(LPCTSTR lpSection, LPCTSTR lpKey); //删除键名public://高级操作:int GetSections(CStringArray& arrSection); //枚举出全部的段名int GetKeyValues(CStringArray& arrKey, CStringArray& arrValue, LPCTSTR lpSection); //枚举出一段内的全部键名及值BOOL DelAllSections();};/*使用方法:CIni ini("c:\\a.ini");int n;/*获得值TRACE("%s",ini.GetValue("段1","键1"));*//*添加值ini.SetValue("自定义段","键1","值");ini.SetValue("自定义段2","键1","值",false);*//*枚举全部段名CStringArray arrSection;n=ini.GetSections(arrSection);for(int i=0;i<n;i++)TRACE("%s\n",arrSection[i]);*//*枚举全部键名及值CStringArray arrKey,arrValue;n=ini.GetKeyValues(arrKey,arrValue,"段1");for(int i=0;i<n;i++)TRACE("键:%s\n值:%s\n",arrKey[i],arrValue[i]); *//*删除键值ini.DelKey("段1","键1");*//*删除段ini.DelSection("段1");*//*删除全部ini.DelAllSections();*/Ini.cpp#include"StdAfx.h"#include"Ini.h"#define MAX_ALLSECTIONS 2048 //全部的段名#define MAX_SECTION 260 //一个段名长度#define MAX_ALLKEYS 6000 //全部的键名#define MAX_KEY 260 //一个键名长度BOOL CIni::SetFileName(LPCTSTR lpFileName){CFile file;CFileStatus status;if (!file.GetStatus(lpFileName, status))return TRUE;m_strFileName = lpFileName;return FALSE;}CString CIni::GetFileName(void){return m_strFileName;}BOOL CIni::SetValue(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpValue, bool bCreate) {TCHAR lpTemp[MAX_PATH] = { 0 };//以下if语句表示如果设置bCreate为false时,当没有这个键名时则返回TRUE(表示出错)//!*&*none-value*&!* 这是个垃圾字符没有特别意义,这样乱写是防止凑巧相同。
delphi开发 ini文件使用详解:ini文件创建、打开、读取、写入操作。
ini文件常用作配置文件使用(1)INI文件的结构:[节点]关键字=值注:INI文件允许有多个节点,每个节点又允许有多个关键字,“=”后面是该关键字的值(类型有串、整型数值和布尔值。
其中字符串存贮在INI文件中时没有引号,布尔真值用1表示,布尔假值注释以分号“;”开头。
(2)INI文件的操作1、在Interface的Uses节增加IniFiles;2、在Var变量定义部分增加一行:inifile:Tinifile;然后,就可以对变量myinifile进行创建、写入等操作了。
procedureTForm1.FormCreate(Sender:TObject);varfilename:string;beginfilename:=ExtractFilePath(paramstr(0))+‘tmp.ini’;inifile:=TInifile.Create(filename);或filename:=getcurrentdir+ 'tmp.ini ';或inifile:=TInifile.Create(‘d:\tmp.ini’);3、打开INI文件:inifile:=Tinifile.create('tmp.ini'); //文件必须存在4、读取关键字的值:a:=inifile.Readstring('节点','关键字',缺省值);// string类型b:=inifile.Readinteger('节点','关键字',缺省值);// integer类型c:=inifile.Readbool('节点','关键字',缺省值);// boolean类型edit1.text:=inifile.Readstring('程序参数,'用户',‘’);checkbox1.checked:=inifile.Readbool('程序参数,'用户',checkbox1.checked);// boolean类型inifile.Readstring('程序参数,'用户',edit1.text);inifile.Readbool('程序参数,'用户',checkbox1.checked);其中[缺省值]为该INI文件不存在该关键字时返回的缺省值。
Ini文件读取类在.h文件中的定义以及相应函数声明。
class CIniFile : public CObject{private:CString m_AppPath; // The Path of Current ApplicationCStringArray m_SectionList; // The List of Section about INI Fileint m_iSectionLen;public:#define MAX_ALLSECTION_LEN 4096#define MAX_FNAME_LEN 260#define BufSize 16384CString m_iniFileName; // The Name of File about .INICIniFile(CString FileName);virtual ~CIniFile();void setFileName(CString FileName);boolean SectionExists(const CString& Section);//boolean ValueExists(const CString& Section,const CString Ident);// READvoid ReadSections();void ReadSection(const CString& Section,CStringArray &Strings);void ReadSectionValues(const CString& Section,CStringArray &Strings);CString ReadString(const CString& Section,const CString& Ident, const CString& Default);//CString ReadString(const CString Section,const CString Ident, const CString Default);int ReadInteger(const CString& Section,const CString& Ident, const int & Default);boolean ReadBool(const CString& Section,const CString& Ident, const boolean& Default);//WRITEvoid WriteString(const CString& Section,const CString& Ident,const CString& Value);void WriteInteger(const CString& Section,const CString& Ident,const int & Value);void WriteBool(const CString& Section,const CString& Ident,const boolean & Value);void EraseSection(CString Section);void DeleteKey(const CString& Section, const CString& Ident);void UpdateFile();CString GetMaxAllSectionLen();boolean FileExists();int FileAge(CString& FileName);};下面是cpp文件中的函数定义#include "stdafx.h"#include "IniFile.h"#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endif//////////////////////////////////////////////////////////////////////// Construction/Destruction///////////////////////////////////////////////////////////////////////***************************** Example *************************** ** FileName = "\\Data\\HGG.ini";*/CIniFile::CIniFile(CString FileName){ASSERT(FileName);m_iniFileName = FileName;ReadSections();}CIniFile::~CIniFile(){UpdateFile();}boolean CIniFile::SectionExists(const CString& Section){ASSERT(m_SectionList.GetSize() > 0);//if (m_SectionList.GetSize() <= 0) return FALSE;for(int i =0;i<m_SectionList.GetSize();i++)if(m_SectionList[i] == Section){return TRUE;break;}return FALSE;}void CIniFile::setFileName(CString FileName){m_iniFileName = FileName;}// READvoid CIniFile::ReadSections(){ASSERT(m_iniFileName);TCHAR AllSection[MAX_ALLSECTION_LEN]={0};TCHAR SectionNames[MAX_FNAME_LEN]={0};DWORD retunValue;// The Result is same abount GetPrivateProfileSectionNames and GetPrivateProfileString //retunValue = GetPrivateProfileSectionNames(AllSection,MAX_ALLSECTION_LEN,m_iniFileName);retunValue = GetPrivateProfileString(NULL,NULL,NULL,AllSection,MAX_ALLSECTION_LEN,m_iniFileN ame);for(int i=0;i<MAX_ALLSECTION_LEN;i++){if(AllSection[i]==0)if(AllSection[i] == AllSection[i+1])break;}int k = 0;m_SectionList.RemoveAll();for(int j=0;j<i+1;j++){SectionNames[k++] = AllSection[j];if(AllSection[j] == NULL){m_SectionList.Add(SectionNames);memset(SectionNames,0,MAX_FNAME_LEN);k = 0;}}}void CIniFile::ReadSection(const CString& Section,CStringArray &Strings){TCHAR Buffer[BufSize]={0};TCHAR* pp=Buffer;CString str;Strings.RemoveAll();if (GetPrivateProfileString(Section, NULL, NULL, Buffer, BufSize,m_iniFileName) != NULL){while (*pp != NULL){Strings.Add(pp);pp += strlen(pp) + 1;}}}void CIniFile::ReadSectionV alues(const CString& Section,CStringArray &Strings){CStringArray KeyList;CString str;ReadSection(Section, KeyList);Strings.RemoveAll();for( int i=0; i<KeyList.GetSize();i++){str = KeyList.GetAt(i) + "=" + ReadString(Section,KeyList.GetAt(i),"");Strings.Add(str);};}CString CIniFile::ReadString(const CString& Section,const CString& Ident, const CString& Default){CString str;ASSERT(m_iniFileName);GetPrivateProfileString(Section,Ident, Default, str.GetBuffer(MAX_FNAME_LEN), MAX_FNAME_LEN, m_iniFileName);str.ReleaseBuffer();return str;}int CIniFile::ReadInteger(const CString& Section,const CString& Ident, const int & Default){CString str;int returnValue,safeSize;returnValue = Default;str = ReadString(Section, Ident, "");safeSize = str.GetLength();returnValue = atoi(str.GetBuffer(safeSize));str.ReleaseBuffer();/*#ifdef UNICODEWideCharToMultiByte(CP_ACP,WC_COMPOSITECHECK,str.GetBuffer(str.SafeStrlen())) atoi(str.GetData()->data());#elsereturnValue = atoi(str.GetData()->data());#endif*/return returnValue;}boolean CIniFile::ReadBool(const CString& Section,const CString& Ident, const boolean& Default){return (ReadInteger(Section, Ident,int(Default)) != 0);}//WRITEvoid CIniFile::WriteString(const CString& Section,const CString& Ident,const CString& Value) {WritePrivateProfileString(Section, Ident,Value,m_iniFileName);}void CIniFile::WriteInteger(const CString& Section,const CString& Ident,const int & Value){CString str;str.Format("%d",Value);WriteString(Section, Ident, str);}void CIniFile::WriteBool(const CString& Section,const CString& Ident,const boolean & Value) {CString Values[2] = {"0","1"};WriteString(Section, Ident, Values[Value]);}void CIniFile::EraseSection(CString Section){ASSERT(WritePrivateProfileString(Section, NULL, NULL, m_iniFileName));}void CIniFile::UpdateFile(){WritePrivateProfileString(NULL, NULL, NULL, m_iniFileName);}void CIniFile::DeleteKey(const CString& Section, const CString& Ident){WritePrivateProfileString(Section, Ident, NULL, m_iniFileName);}CString CIniFile::GetMaxAllSectionLen(){CString str;str.Format("%d",MAX_ALLSECTION_LEN);return str;}boolean CIniFile::FileExists(){ASSERT(m_iniFileName);return (FileAge(m_iniFileName) != -1);}int CIniFile::FileAge(CString& FileName){HANDLE Handle;WIN32_FIND_DA TA FindData;FILETIME LocalFileTime;WORD HiWord,LoWord;int resultValue;Handle = FindFirstFile(FileName, &FindData);if (Handle != INV ALID_HANDLE_V ALUE){FindClose(Handle);if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0){FileTimeToLocalFileTime(&FindData.ftLastWriteTime, &LocalFileTime);if(FileTimeToDosDateTime(&LocalFileTime,&HiWord,&LoWord)){resultValue = HiWord;resultValue = resultValue << sizeof(HiWord)*8 | LoWord;return resultValue;}}}return (-1); }。
ini文件只知道节名,读取节下所有值的方法qt1.引言1.1 概述概述INI文件是一种常见的配置文件格式,它被广泛用于存储和管理应用程序的配置信息。
INI文件由一系列的节(section)和键值对(key-value)组成。
每个节包含一组相关的键值对,用来描述特定的配置项。
在读取INI 文件时,通常可以根据节名和键名来获取对应的值。
然而,在某些情况下,我们可能只知道节的名称,而不清楚该节下有哪些键值对。
本文将介绍如何通过Qt框架提供的方法来读取INI文件中某个节下的所有键值对。
首先,我们需要了解Qt框架中关于INI文件的相关类和函数。
Qt提供了一个名为QSettings的类,它是用于读写配置信息的工具类。
QSettings类支持INI文件格式,并提供了方便的方法来读取和写入INI 文件中的配置项。
在使用QSettings类读取INI文件时,我们可以先使用QSettings的构造函数来指定INI文件的路径,然后使用value()函数来获取指定节下的键值对。
为了读取某个节下的所有键值对,我们可以使用childGroups()函数来获取所有的子节名,然后再遍历每个子节获取其对应的键值对。
下面是一个简单的示例代码,展示了如何使用Qt框架中的QSettings 类来读取INI文件中某个节下的所有键值对:cppinclude <QSettings>include <QDebug>void readIniFile(const QString& filePath){QSettings settings(filePath, QSettings::IniFormat);QStringList sectionList = settings.childGroups();foreach (const QString& section, sectionList) {settings.beginGroup(section);QStringList keys = settings.childKeys();foreach (const QString& key, keys) {QString value = settings.value(key).toString();qDebug() << "Section:" << section << "Key:" << key << "Value:" << value;}settings.endGroup();}}int main(){QString filePath = "config.ini";readIniFile(filePath);return 0;}以上代码中,readIniFile()函数用于读取INI文件中某个节下的所有键值对。
ini文件编写方法一。
ini 文件是一种常见的配置文件格式,在很多软件和系统中都有广泛应用。
要编写一个好的 ini 文件,首先得搞清楚它的基本结构。
1.1 ini 文件通常由节(Section)和键值对(Key-Value Pair)组成。
节就像是一个个分类的文件夹,而键值对则是在这些文件夹里存放的具体信息。
比如说,[Settings] 这就是一个节的名称。
1.2 键值对呢,就是像“Key=Value”这样的形式。
比如说“FontSize=12”,“FontSize”是键,“12”就是值。
二。
在编写 ini 文件时,有一些要点得特别注意。
2.1 命名要清晰明了。
节名和键名都得让人一眼就能看出它是干啥的。
别整那些让人摸不着头脑的名字,不然回头自己都搞不清楚。
2.2 格式要规范。
每行一个键值对,别乱糟糟的,不然读起来就跟一团乱麻似的。
2.3 注释也很重要。
有时候给自己或者别人留个注释,说明一下这个键值是干啥用的,为啥这么设置,能省不少事儿。
三。
再来说说怎么修改和读取 ini 文件。
3.1 有很多编程语言都能处理 ini 文件。
比如说 Python 就有专门的库来读取和修改 ini 文件,用起来挺方便的。
3.2 但不管用啥方法,都得小心谨慎,别一不小心把重要的配置给改坏了,那可就麻烦大了。
编写 ini 文件虽然不算特别复杂,但也得用心去做,才能让它发挥应有的作用。
就像盖房子,基础打牢了,房子才能结实。
可别马马虎虎,不然到时候出了问题,就得返工,费时又费力!。
ini文件格式INI文件由节、键、值组成。
节[section]参数(键=值)name=value下面是一个ini文件的例子[Section1Name]KeyName1=value1KeyName2=value2...[Section2Name]KeyName21=value21KeyName22=value22其中:[Section1Name]用来表示一个段落。
因为INI文件可能是项目中共用的,所以使用[Section Name]段名来区分不同用途的参数区。
例如:[Section1Name]表示传感器灵敏度参数区;[Section2Name]表示测量通道参数区等等。
注解:使用分号表示(;)。
在分号后面的文字,直到该行结尾都全部为注解。
二Qt写ini文件[cpp]view plaincopyprint?1#include<QtCore/QCoreApplication>2#include<QSettings>3int main(int argc,char*argv[])4{5QCoreApplication a(argc,argv);6//Qt中使用QSettings类读写ini文件7//QSettings构造函数的第一个参数是ini文件的路径,第二个参数表示针对ini文件,第三个参数可以缺省8QSettings*configIniWrite=new QSettings("hahaya.ini",QSettings::IniFormat);9//向ini文件中写入内容,setValue函数的两个参数是键值对10//向ini文件的第一个节写入内容,ip节下的第一个参数11configIniWrite->setValue("/ip/first","192.168.0.1");12//向ini文件的第一个节写入内容,ip节下的第二个参数13configIniWrite->setValue("ip/second","127.0.0.1");14//向ini文件的第二个节写入内容,port节下的第一个参数15configIniWrite->setValue("port/open","2222");16//写入完成后删除指针17delete configIniWrite;1819return a.exec();20}[cpp]view plain copyprint?21#include<QtCore/QCoreApplication>22#include<QSettings>23int main(int argc,char*argv[])24{25QCoreApplication a(argc,argv);26//Qt中使用QSettings类读写ini文件27//QSettings构造函数的第一个参数是ini文件的路径,第二个参数表示针对ini文件,第三个参数可以缺省28QSettings*configIniWrite=new QSettings("hahaya.ini",QSettings::IniFormat);29//向ini文件中写入内容,setValue函数的两个参数是键值对30//向ini文件的第一个节写入内容,ip节下的第一个参数31configIniWrite->setValue("/ip/first","192.168.0.1");32//向ini文件的第一个节写入内容,ip节下的第二个参数33configIniWrite->setValue("ip/second","127.0.0.1");34//向ini文件的第二个节写入内容,port节下的第一个参数35configIniWrite->setValue("port/open","2222");36//写入完成后删除指针37delete configIniWrite;3839return a.exec();40}运行程序后,打开程序目录下的hahaya.ini文件,结果如下图所示:三Qt读ini文件[cpp]view plaincopyprint?41#include<QtCore/QCoreApplication>42#include<QSettings>43#include<QString>44#include<QDebug>45int main(int argc,char*argv[])46{47QCoreApplication a(argc,argv);4849QSettings*configIniRead=new QSettings("hahaya.ini",QSettings::IniFormat);50//将读取到的ini文件保存在QString中,先取值,然后通过toString()函数转换成QString类型51QString ipResult=configIniRead->value("/ip/second").toString();52QString portResult=configIniRead->value("/port/open").toString();53//打印得到的结果54qDebug()<<ipResult;55qDebug()<<portResult;56//读入入完成后删除指针57delete configIniRead;58return a.exec();59}[cpp]view plain copyprint?60#include<QtCore/QCoreApplication>61#include<QSettings>62#include<QString>63#include<QDebug>64int main(int argc,char*argv[])65{66QCoreApplication a(argc,argv);6768QSettings*configIniRead=new QSettings("hahaya.ini",QSettings::IniFormat);69//将读取到的ini文件保存在QString中,先取值,然后通过toString()函数转换成QString类型70QString ipResult=configIniRead->value("/ip/second").toString();71QString portResult=configIniRead->value("/port/open").toString();72//打印得到的结果73qDebug()<<ipResult;74qDebug()<<portResult;75//读入入完成后删除指针76delete configIniRead;77return a.exec();78}程序运行截图:。
在Lua中,读写INI文件需要使用外部库或模块。
一种常见的方式是使用Lua的标准库中的io模块来实现。
下面是一个使用io模块读写INI文件的示例代码。
首先,我们需要定义一个函数来读取INI文件的内容:function read_ini_file(filename)local section =""local data ={}-- 打开文件local file =io.open(filename,"r")if not file thenerror("无法打开文件: ".. filename)end-- 逐行读取文件内容for line in file:lines()doline = line:gsub("%s+","")-- 去掉空格-- 如果是一个新的节(section),则保存节名local s = line:match("^%[(.+)%]$")if s thensection = sdata[section]={}end-- 如果是键值对,则保存键和值local key, value = line:match("^(.+)=(.+)$")if key and value thendata[section][key]= valueendend-- 关闭文件file:close()return dataend这个函数接受一个文件名作为参数,并返回一个包含INI文件内容的Lua表。
表的键是节名,值是包含键值对的Lua表。
例如,给定以下INI文件的内容:[Section1]key1=value1key2=value2[Section2]key3=value3调用read_ini_file("example.ini")将返回一个Lua表:{Section1 ={key1 ="value1",key2 ="value2"},Section2 ={key3 ="value3"}}接下来,我们可以定义一个函数来写入INI文件的内容:function write_ini_file(filename, data)-- 打开文件local file =io.open(filename,"w")if not file thenerror("无法打开文件: ".. filename)end-- 逐个节写入for section, keys in pairs(data)do-- 写入节名file:write("[".. section .."]\n")-- 写入键值对for key, value in pairs(keys)dofile:write(key .."=".. value .."\n")end-- 写入空行分隔节file:write("\n")end-- 关闭文件file:close()end这个函数接受一个文件名和一个包含INI文件内容的Lua表作为参数,并将内容写入文件中。
python简单读写ini⽂件1、创建ini⽂件2、认识configparse类中基础⽅法cfg_obj = configparser.ConfigParser() #创建对象cfg_obj.read(conf_file_path) #读取配置⽂件sections = cfg_obj.sections()#获取配置⽂件中所有的section节点options = cfg_obj.options("default")#获取对应节点下的所有keyfor sec in sections:print(cfg_obj.options(sec))#可使⽤for循环获取ini⽂件中各个节点下的key值value = cfg_obj.get("default","path") #获取对应的valuecfg_obj.set("default","path111","value1111") #设置key和value到ini⽂件cfg_obj.add_section("default") #增加section到⽂件cfg_obj.remove_section("default") #移除section节点数据cfg_obj.remove_option("default","patha") #移除节点下的optionconfig_file_obj = open( conf_file_path,"w") #创建ini⽂件对象cfg_obj.write(config_file_obj) #写⼊⽂件judge_value_is_exist = cfg_obj.has_section("default") #判断section节点是否存在judge_value_is_exist2 = cfg_obj.has_option("default","path")#判断节点下的key是否存在3、封装,创建⼀个读取ini⽂件的⼯具类1)创建初始化函数class ConfigUtils:def __init__(self,config_file_path):self.cfg_path = config_file_pathself.cfg =configparser.ConfigParser()self.cfg.read(self.cfg_path)2)创建读取配置⽂件值的⽅法def read_value(self,section,key):value = self.cfg.get(section,key)return value3)创建写⼊配置⽂件的⽅法def write_value(self,section,key,value):self.cfg.set( section,key,value )config_file_obj = open( self.cfg_path , "w")self.cfg.write(config_file_obj)config_file_obj.flush()config_file_obj.close()cfg_obj.set("default","path111","value1111")。
C#中读写INI配置文件
在作应用系统开发时,管理配置是必不可少的。
例如数据库服务器的配置、安装和更新配置等等。
由于Xm l的兴起,现在的配置文件大都是以xml文档来存储。
比如Visual 自身的配置文件Mashine.config,的配置文件Web.Config,包括我在介绍Rem oting中提到的配置文件,都是xm l的格式。
传统的配置文件ini已有被xml文件逐步代替的趋势,但对于简单的配置,ini文件还是有用武之地的。
ini文件其实就是一个文本文件,它有固定的格式,节Secti on的名字用[]括起来,然后换行说明key的值:
[section]
key=value
如数据库服务器配置文件:
DBServer.ini
[Server]
Nam e=localhost
[DB]
Nam e=NorthWind
using using using using
nam {
{
} }
Section参数、Key参数和IniFilePath不用再说,Value参数表明key的值,而这里的NoText 对应API函数的def参数,它的值由用户指定,是当在配置文件中没有找到具体的Value时,就用NoTex t的值来代替。
纯CC++封装的INI⽂件读写类// CIniHelper.h Copyallright By DJH5520 2017-10#ifndef _CINIHELPER_H_#define _CINIHELPER_H_#include <unordered_map> // 查找速度O(1)#include <vector>#include <string>#include <fstream>#include <cassert>#include <exception>#include <iterator>#include <algorithm>#include <functional>#include <cstdio>// 键值对结构struct SKeyValue{std::string m_strKey;std::string m_strValue;};// Section结构struct SSection{std::string m_strSectionName; // Section名称std::vector<SKeyValue> m_kvPairs;// 当前Section下所有键值对,按顺序存储};class CIniHelper{private:// 禁⽌外部构造CIniHelper() = default;// 禁⽌拷贝CIniHelper(const CIniHelper& other) = delete;CIniHelper& operator=(const CIniHelper& other) = delete;~CIniHelper() { DumpToFile(); }public:/*!* 功能:获取单例对象指针(注:直接采⽤饿汉模式以保证线程安全)* 参数:⽆* 返回值:内部创建的单例对象指针*/static CIniHelper* GetInstance();/*!* 功能:释放单例对象指针(在任何地⽅均不需要使⽤本类时,调⽤该函数delete创建的单例对象,否则只在程序结束时释放)* 参数:⽆* 返回值:void*/static void FreeInstance();/*!* 功能:加载ini⽂件,使⽤前必须先加载ini* 参数:strPath:ini⽂件的路径* 返回值:void*/void LoadIniFile(const std::string& strPath);/*!* 功能:将当前ini内容写⼊⽂件* 参数:void* 返回值:成功返回0,失败返回-1*/int DumpToFile() { return WriteFile(m_strFilePath); }//==================================读写⽅法,模拟Windows API函数格式=================================// /*!* 功能:按int类型获取指定Section下指定Key的Value值* 参数:strSecName:指定查找的节点名称strKeyName:指定查找的KeynDefault:当未找到时,返回的默认值* 返回值:返回找到的value值*/int GetPrivateProfileInt(const std::string& strSecName, const std::string& strKeyName, int nDefault);/*!* 功能:按double类型获取指定Section下指定Key的Value值* 参数:strSecName:指定查找的节点名称strKeyName:指定查找的KeydDefault:当未找到时,返回的默认值* 返回值:返回找到的value值*/double GetPrivateProfileDouble(const std::string& strSecName, const std::string& strKeyName, double dDefault);/*!* 功能:按string类型获取指定Section下指定Key的Value值* 参数:strSecName:指定查找的节点名称strKeyName:指定查找的KeystrDefault:当未找到时,返回的默认值* 返回值:返回找到的value值*/std::string GetPrivateProfileString(const std::string& strSecName, const std::string& strKeyName, const std::string& strDefault); /*!* 功能:获取指定Section下所有的键值对* 参数:strSecName:指定查找的节点名称kvPairs:输出参数,⽤于保存获取到的键值对* 返回值:获取成功返回0,失败返回-1*/int GetPrivateProfileSection(const std::string& strSecName, std::vector<SKeyValue>& kvPairs);/*!* 功能:获取ini⽂件中所有Section的名称* 参数:vecSecNames:输出参数,⽤于保存获取到的名称* 返回值:⽆*/void GetPrivateProfileSectionNames(std::vector<std::string>& vecSecNames);/*!* 功能:写⼊或修改指定Section下指定Key的Value值(不存在则写⼊,已存在则修改value值)* 参数:strSecName:写⼊或修改的节点名称strKeyName:写⼊或修改的键名strValue:写⼊或修改的键的值* 返回值:成功返回0,失败返回-1*/int WritePrivateProfileString(const std::string& strSecName, const std::string& strKeyName, const std::string& strValue); private:///按⾏读取⽂件内容void ReadFile(const std::string& strPath);///按⾏写⼊⽂件int WriteFile(const std::string& strPath);///去除字符串⾸尾空⽩void trim(std::string& str);///去除字符串左边空⽩void TrimLeft(std::string& str);///去除字符串右边空⽩void TrimRight(std::string& str);///忽略⼤⼩写⽐较字符串int CompareNocase(const std::string& str1, const std::string& str2);///判断是否是Sectioninline bool IsSection(const std::string& str);///判断⼀⾏字符串是否是键值对bool IsKeyValuePairs(const std::string& str);///获取所有的Sectionvoid GetAllSections();///从键值对⾏提取键值对,使⽤前提:调⽤之前已经判断该⾏就是键值对bool GetKeyValuePair(const std::string& strLine, std::string& strKey, std::string& strValue);#if 0bool GetKeyValue(const std::string& strLine, SKeyValue& kvPair);#endif///根据Section和Key查找Value,未找到则返回空串std::string GetValueString(const std::string& strSecName, const std::string& strKeyName);///获取最第⼀个注释符号的位置(⽀持注释符号:"//" "#" ";")size_t GetCommentPos(const std::string& strLine);private:/// ini⽂件路径std::string m_strFilePath;/// ini⽂件内容std::vector<std::string> m_fileContent;#if 0///所有Section,选⽤vector容器以保留原⽂顺序,追求效率可以使⽤map/hash这种容器std::vector<SSection> m_sections;#endif///单例对象指针static CIniHelper* m_instance;///核⼼成员:<Section, <Key, Value>> unordered_map缺点是⽆法保持原⽂顺序,只是查询效率⾼,需要保持顺序建议⽤顺序性容器std::unordered_map<std::string, std::unordered_map<std::string, std::string>> m_allSection;};#endif#include "CIniHelper.h"// 单例对象初始化CIniHelper* CIniHelper::m_instance = new CIniHelper;CIniHelper* CIniHelper::GetInstance(){return m_instance;}void CIniHelper::FreeInstance(){if (m_instance){delete m_instance;m_instance = nullptr;}}void CIniHelper::LoadIniFile(const std::string& strPath){// 清空所有容器// 关于vector容器:// clear⽅法并不会真正释放已经分配的内存,查看其源码可知它只是调⽤内部元素的析构函数,已分配的内存并不会释放,可以调⽤capacity查看其容量并未改变 // 这是vector的内存优化策略,当再次使⽤该容器时,它只需要调⽤构造函数对已有的内存初始化即可,vector真正释放内存是在其⾃⾝析构时// 使⽤swap将其与⼀个空的临时vector对象交换,可以将旧的内存转移到临时vector,当临时对象析构时旧的内存就释放了//m_fileContent.clear();m_fileContent.swap(std::vector<std::string>());// map容器的erase和clear时会释放内存的(根据STL源码剖析)m_allSection.clear();// 读取ini⽂件内容到容器assert(strPath != "");m_strFilePath = strPath;ReadFile(m_strFilePath);// 解析ini中所有SectionGetAllSections();}int CIniHelper::GetPrivateProfileInt(const std::string& strSecName, const std::string& strKeyName, int nDefault){std::string strValue = GetValueString(strSecName, strKeyName);if (strValue.empty()){return nDefault;}return std::stoi(strValue);}double CIniHelper::GetPrivateProfileDouble(const std::string& strSecName, const std::string& strKeyName, double dDefault) {std::string strValue = GetValueString(strSecName, strKeyName);if (strValue.empty()){return dDefault;}return std::stod(strValue);}std::string CIniHelper::GetPrivateProfileString(const std::string& strSecName,const std::string& strKeyName,const std::string& strDefault){std::string strValue = GetValueString(strSecName, strKeyName);if (strValue.empty()){return strDefault;}else{return strValue;}}int CIniHelper::GetPrivateProfileSection(const std::string& strSecName, std::vector<SKeyValue>& kvPairs){try{kvPairs.clear();// 查找Section下所有的键值对⼀般需要保持顺序,unordered_map没法⽤,只能⽤顺序容器或去原⽂查找std::string strInnerSec = "[" + strSecName + "]";auto it = m_fileContent.cbegin();for (; it != m_fileContent.cend(); ++it){if (IsSection(*it) && (*it) == strInnerSec)break; // 找到了}if (it != m_fileContent.cend()){// 继续提取该Section下⾯,直⾄下⼀个Section之间的KeyValue++it;for (; it != m_fileContent.cend(); ++it){if (IsSection(*it)){break; // 已到达下⼀个Section}else if (IsKeyValuePairs(*it)){SKeyValue kv;if (GetKeyValuePair(*it, kv.m_strKey, kv.m_strValue)){kvPairs.emplace_back(kv);}}}}}catch (const std::exception&){return -1;}#if 0std::string strInnerSec = "[" + strSecName + "]";for (auto iter = m_sections.cbegin(); iter != m_sections.cend(); ++iter){auto& sec = *iter;if (sec.m_strSectionName == strInnerSec){kvPairs = sec.m_kvPairs;return0;}}#endifreturn0;}void CIniHelper::GetPrivateProfileSectionNames(std::vector<std::string>& vecSecNames){vecSecNames.clear();// 获取Section⼀般需要保持顺序,unordered_map没法⽤,只能⽤顺序容器原⽂查找for (auto& strLine : m_fileContent){if (IsSection(strLine)){std::string strSec = strLine.substr(1, strLine.length() - 2); // 去除"[" "]"即第⼀个和最后⼀个trim(strSec); // 去除空⽩vecSecNames.emplace_back(strSec);}}#if 0for (auto it = m_sections.cbegin(); it != m_sections.cend(); ++it){vecSecNames.push_back(it->m_strSectionName);}#endif}int CIniHelper::WritePrivateProfileString(const std::string& strSecName, const std::string& strKeyName, const std::string& strValue) {try{// 写⼊Section的键值对⼀般需要保持顺序,unordered_map没法⽤,只能⽤顺序容器原⽂查找std::string strInnerSec = "[" + strSecName + "]";// 查找Sectionauto it = m_fileContent.begin();for (; it != m_fileContent.end(); ++it){if (IsSection(*it) && (*it) == strInnerSec)break;// 找到了指定的Section}bool bFindKey = false;if (it != m_fileContent.end()){// 找到了指定的Section,继续查找Section下⾯是否存在指定的Key++it; // 跳到下⼀⾏for (; it != m_fileContent.end(); ++it){// 是否是键值对if (IsKeyValuePairs(*it)){if ((*it).find(strKeyName) != std::string::npos){// 找到了KeybFindKey = true;// 获取该Key原来的值std::string strOldValue = GetPrivateProfileString(strSecName, strKeyName, "");// 如果⼀致则不⽤修改if (strOldValue == strValue) return0;// 替换旧的valueif (strOldValue == ""){// 原来的Value为空(*it) = strKeyName + "=" + strValue;}else{size_t oldValuePos = (*it).find(strOldValue);if (oldValuePos != std::string::npos){(*it).replace(oldValuePos, strOldValue.length(), strValue); // 替换}else{// 没找到旧的值,直接修改为新的值(*it) = strKeyName + "=" + strValue;}}// 同步更新m_allSection[strInnerSec][strKeyName] = strValue;break;}continue;}else if ((bFindKey == false) && ((it + 1) == m_fileContent.end()) && IsSection(*(it + 1))){// 提前检查下⼀⾏是不是新的Section,或者已经是最后⼀⾏, 如果是且未找到Key,则证明这是⼀个新的Key,则将其插⼊当前Section的最后 // 插⼊这个新的key, insert函数是在指定位置前⼀个位置插⼊,所以要加+才表⽰在当前位置后⾯插⼊std::string strPair = strKeyName + "=" + strValue;m_fileContent.insert(it + 1, strPair);// 同步更新m_allSection[strInnerSec][strKeyName] = strValue;break;}}}else{// 未找到指定Section,则这是⼀个新的Section,将其添加到⽂件最后m_fileContent.push_back(strInnerSec);m_fileContent.push_back(strKeyName + "=" + strValue);// 同步更新std::unordered_map<std::string, std::string> kv;kv.emplace(strKeyName, strValue);m_allSection.emplace(strInnerSec, kv);}// 每次修改都保存⽂件效率不⾼,可以考虑使⽤DumpToFile接⼝,让⽤户不再修改时再真正保存到⽂件,或者析构时写⼊// return WriteFile(m_strFilePath);return0;}catch (const std::exception&){return -1;}}//===============================================================================================//void CIniHelper::ReadFile(const std::string& strPath){try{std::ifstream fs;fs.open(strPath);std::string strLine;// 按⾏读取⽂本⽂件while (fs){std::getline(fs, strLine);m_fileContent.emplace_back(strLine); // 效率⽐push_back⾼}fs.close();}catch (const std::exception&){std::abort();}}int CIniHelper::WriteFile(const std::string& strPath){std::string strTempFilePath = strPath + ".tmp";try{std::ofstream fs;// 先将内容写⼊临时⽂件,写⼊成功后替换原⽂件,防⽌写⼊失败时破坏原⽂件fs.open(strTempFilePath);auto it = m_fileContent.cbegin();for (; it != (m_fileContent.cend() - 1); ++it)fs << *it << "\n";}// 最后⼀⾏不加换⾏符fs << *it;fs.close();}catch (const std::exception&){return -1;}std::remove(strPath.c_str()); // 删除原⽂件std::rename(strTempFilePath.c_str(), strPath.c_str()); // 将临时⽂件重命名return0;}void CIniHelper::trim(std::string& str){if (!str.empty()){const char strSpace[] = " \t\n\r\f\v"; // 空⽩字符集str.erase(0, str.find_first_not_of(strSpace));str.erase(str.find_last_not_of(strSpace) + 1);}}void CIniHelper::TrimLeft(std::string& str){if (!str.empty()){const char strSpace[] = " \t\n\r\f\v"; // 空⽩字符str.erase(0, str.find_first_not_of(strSpace));}}void CIniHelper::TrimRight(std::string& str){if (!str.empty()){const char strSpace[] = " \t\n\r\f\v"; // 空⽩字符str.erase(str.find_last_not_of(strSpace) + 1);}}int CIniHelper::CompareNocase(const std::string& str1, const std::string& str2){std::string s1, s2;// 均转换成⼩写后⽐较std::transform(str1.cbegin(), str1.cend(), back_inserter(s1), ::tolower);std::transform(str2.cbegin(), str2.cend(), back_inserter(s2), ::tolower);return pare(s2);}bool CIniHelper::IsSection(const std::string& str){size_t len = str.length();// ⼀个合法的Section长度最少为3,且第⼀个和最后⼀个字符分别是'['和']', 如:[Config] if (len >= 3 && str.at(0) == '[' && str.at(len - 1) == ']'){return true;}elsereturn false;}bool CIniHelper::IsKeyValuePairs(const std::string& str){if (str.length() >= 3 && str.find('=') != std::string::npos){return true;}return false;}void CIniHelper::GetAllSections(){// 从容器中获取⽂件中的每⼀⾏⽂本,并解析for (auto& strLine : m_fileContent)static std::string SectionName = ""; // 静态变量,⽤于记住键值对上⾯的Section名// 去除⾸位空⽩字符trim(strLine);// 判断⽂本内容是否是Section还是Section下的键值对if (IsSection(strLine)){// SectionSectionName = strLine;// 记住Section名,如果该Section存在键值对,则下⼀⾏⽂本的内容就是其键值对m_allSection.emplace(SectionName, std::unordered_map<std::string, std::string>()); // Section对应的键值对容器暂时为空continue;}else if (IsKeyValuePairs(strLine)){// 键值对// 提取Key和Valuestd::string strKey, strValue;if (GetKeyValuePair(strLine, strKey, strValue)){// 将其插⼊对应的Section下⾯if (!SectionName.empty()){auto& kvMap = m_allSection.at(SectionName);kvMap.emplace(strKey, strValue);}}}}#if 0// 解析⽂件每⼀⾏,获取键值对for (auto iter = m_fileContent.cbegin(); iter != m_fileContent.cend(); ++iter){std::string strLine = *iter;// 删除⼀⾏的前后空⽩trim(strLine);// 判断类型if (IsSection(strLine)){// 先尾部插⼊⼀个SectionSSection tmp;tmp.m_strSectionName = strLine;m_sections.push_back(tmp);}else if (IsKeyValuePairs(strLine)){// 如果是键值对,则需要将其放到它对应的Section下⾯(最后⼀个插⼊的那个Section就是,它上⾯的Section)SSection& sec = m_sections.back();// 提取Key和ValueSKeyValue tmp;if (GetKeyValue(strLine, tmp)){sec.m_kvPairs.push_back(tmp);}}}#endif}bool CIniHelper::GetKeyValuePair(const std::string& strLine, std::string& strKey, std::string& strValue){strKey = "", strValue = "";// 提取Key(不能为空)size_t posEqual = strLine.find('='); // 找到第⼀个'='位置if (posEqual == 0) return false; // 如果第1个字符就是'='则不是键值对strKey = strLine.substr(0, posEqual); // 截取"="前⾯的字符串作为Key// 去除空⽩trim(strKey);if (strKey.empty()) return false;// 提取value(可以为空)// 获取第⼀个注释符号的位置,⽬前⽀持的注释符有 "//" '#' ';'size_t posComment = GetCommentPos(strLine);if ((posComment > posEqual + 1) && (posComment != std::string::npos)) // 检查注释符位置是否合法{// 有注释符号,截取"="后⾯到注释符号之间的内容作为ValuestrValue = strLine.substr(posEqual + 1, posComment - posEqual - 1);}else{// 没有注释则直接截取=后⾯的内容strValue = strLine.substr(posEqual + 1);trim(strValue);return true;}#if 0bool CIniHelper::GetKeyValue(const std::string& strLine, SKeyValue& kvPair){// 提取Keysize_t posEqual = strLine.find('='); // 找到第⼀个'='位置if (posEqual == 0) return false; // 如果第⼀个字符就是'='则⾮法std::string strKey = strLine.substr(0, posEqual);// 去除左右空⽩trim(strKey);if (strKey.empty()) return false;// 提取valuestd::string strValue = "";// 获取第⼀个注释符号的位置size_t posComment = GetCommentPos(strLine);if ((posComment > posEqual + 1) && (posComment != std::string::npos)) // 检查位置是否合法{// 有注释符号,截取=后⾯到注释符号之间的内容strValue = strLine.substr(posEqual + 1, posComment - posEqual - 1);}else{// 没有注释截取=后⾯的内容strValue = strLine.substr(posEqual + 1);}// 去除空⽩trim(strValue);kvPair.m_strKey = strKey;kvPair.m_strValue = strValue;return true;}#endifstd::string CIniHelper::GetValueString(const std::string& strSecName, const std::string& strKeyName) {std::string strResult = "";std::string strInterSec = "[" + strSecName + "]"; // eg: [Config]// 查找对应Sectionauto sec = m_allSection.find(strInterSec);if (sec != m_allSection.end()){// 存在则继续查找Keyauto& kvPair = sec->second;auto it = kvPair.find(strKeyName);if (it != kvPair.end()){// 找到了strResult = it->second;}}#if 0std::string strInterSec = "[" + strSecName + "]";// 查找Sectionfor (auto iter = m_sections.cbegin(); iter != m_sections.cend(); ++iter){auto& sec = *iter;// 找到了Sectionif (sec.m_strSectionName == strInterSec){// 继续查找Keyconst std::vector<SKeyValue>& kvs = sec.m_kvPairs;for (auto it = kvs.cbegin(); it != kvs.cend(); ++it){// 找到了Keyif (strKeyName == (*it).m_strKey){strResult = (*it).m_strValue;break;}}break;}}#endifreturn strResult;}size_t CIniHelper::GetCommentPos(const std::string& strLine){size_t spos[3] = { 0 }; // pos[0]表⽰"//"第⼀次出现的位置,pos[1]表⽰"#",pos[2]表⽰";"第⼀次出现的位置spos[0] = strLine.find("//");spos[1] = strLine.find("#");spos[2] = strLine.find(";");// 取最⼩值,即最先出现的注释符位置size_t* pos = std::min_element(std::begin(spos), std::end(spos));return *pos;}//=======================================================================================//#include "CIniHelper.h"#include <cstdio>#include <cstdlib>#include <iostream>#include <ctime>clock_t g_start = 0, g_end = 0;int main(int argc, char* argv[]){#if 1g_start = std::clock();CIniHelper* pini = CIniHelper::GetInstance();g_end = std::clock();std::cout << ">>>>>>>>>>>>>>GetInstance() Use Time:" << g_end - g_start << "ms\n"<< std::endl;// ⾸次使⽤时,必须加载ini⽂件,最耗时的函数g_start = std::clock();pini->LoadIniFile("./Config.ini");g_end = std::clock();std::cout << ">>>>>>>>>>>>>>LoadIniFile() Use Time:" << g_end - g_start << "ms\n" << std::endl;// 获取int值g_start = std::clock();std::cout << "[PN9Test]DummyFrame=" << pini->GetPrivateProfileInt("PN9Test", "DummyFrame", 0) << std::endl;g_end = std::clock();std::cout << ">>>>>>>>>>>>>>GetPrivateProfileInt() Use Time:" << g_end - g_start << "ms\n" << std::endl;// 获取double类型g_start = std::clock();std::cout << "[Capture_D50]DFOV=" << pini->GetPrivateProfileDouble("Capture_D50", "DFOV", 0) << std::endl;g_end = std::clock();std::cout << ">>>>>>>>>>>>>>GetPrivateProfileDouble() Use Time:" << g_end - g_start << "ms\n" << std::endl;// 获取stringg_start = std::clock();std::cout << "[TestItems]LightDefectPixel=" << pini->GetPrivateProfileString("TestItems", "LightDefectPixel", "") << std::endl; g_end = std::clock();std::cout << ">>>>>>>>>>>>>>GetPrivateProfileString() Use Time:" << g_end - g_start << "ms\n" << std::endl;// 获取整个Section下所有键值对std::vector<SKeyValue> kvPairs;g_start = std::clock();pini->GetPrivateProfileSection("TestItems", kvPairs);g_end = std::clock();std::cout << "[Section TestItems]" << std::endl;for (auto it = kvPairs.begin(); it != kvPairs.end(); ++it){std::cout << it->m_strKey << "=" << it->m_strValue << std::endl;}std::cout << ">>>>>>>>>>>>>>GetPrivateProfileSection() Use Time:" << g_end - g_start << "ms\n" << std::endl;// 回写⽂件g_start = std::clock();pini->WritePrivateProfileString("Capture_SFR145", "Test_Ver", "10.2.8");g_end = std::clock();std::cout << ">>>>>>>>>>>>>>WritePrivateProfileString() Use Time:" << g_end - g_start << "ms\n" << std::endl;CIniHelper::FreeInstance();#endifsystem("pause"); return0;}。
在VB6中用WINDOWS API函数读写INI文件INI文件在Windows3.2的时代扮演着极其重要的角色,主要用于保存软件参数的设置。
但到了Windows95/98的年代,微软推出了注册表,一般要求软件将所有的参数设置全保存到注册表中去。
这样一来,当用户安装的软件越来越多的时候,就会导致注册表越来越庞大,从而令到系统运行速度变慢,稳定性变差。
所以,在某些情况下,如:软件需要保存的数据不多或要制作“绿色软件”时,我们仍然经常用到INI文件。
《家用电脑》自1999年以来已经有不少文章介绍过在编程时如何读写INI文件的方法,但多是基于C++或Delphi的,对于目前最为流行的编程语言之一的Visual Basic却没有提及。
现笔者根据自己的使用经验,将VB中读写INI文件的方法总结出来,以和各位“大虾”共同探讨一下。
方法当然也是利用Windows本身提供的API函数。
对INI文件的读写操作,Windows 提供了如下几个常用的 API函数:GetPrivateProfileInt()、GetPrivateProfileSection()、GetPrivateProfileString()、WritePrivateProfileSection()、WritePrivateProfileString()。
由于在《家用电脑》1999年第21期的《利用Windows API函数在Delphi中对INI文件读写》(以下简称《利》文)中已经对上述5个函数作了详细的介绍。
虽然《利》文介绍的方法是在Delphi中实现的,但除了声明方式外,函数的功能和参数的含义是相同的,所以,笔者就不再详述了,在此仅给出它们在VB中的声明方式及作用:Public Declare Function GetPrivateProfileInt Lib ″kernel32″Alias ″GetPrivateProfileIntA″ (ByVal lpApplicationName As String,ByVal lpKeyName As String, ByVal nDefault As Long, ByVal lpFileName AsString) As Long。
selenium+python⾃动化测试--读取配置⽂件(.ini)前⾔:今天为什么要整理读取配置⽂件呢?原因是:公司正在做的项⽬,操作页⾯时都是根据路由跳转,由于⾃⼰经验尚浅,将url地址写在每个⽤例中,导致每次开发⼀更改路由,我就要去每个页⾯中修改url地址,光来来回回找页⾯就很费时间,所以就想到了⽤配置⽂件,将所有url地址放在⼀个⽂件中,页⾯⽤到哪个时读取哪个。
⼀、基础了解iniini配置⽂件格式如下:;这⾥是注释[section0]key0 = value0key1 = value1[section1]key2 = value2key3 = value3section不能重复,⾥⾯数据通过section去查找,每个seletion下可以有多个key和vlaue的键值对,注释⽤英⽂分号(;)configparser通过python3⾥⾯⾃带configparser模块来读取ini⽂件。
# python3import configParser如果注释⾥⾯有中⽂的话,这⾥代码跟python2是有点区别的,python2⾥⾯直接conf.read(cfgpath)就可以了,python3需要加个参数:encoding="utf-8"conf.read(cfgpath, encoding="utf-8")⼆、代码编写分别在common⽂件夹下新建配置⽂件:config.ini 和读取配置⽂件:readConf.py ,然后编写代码...1、配置⽂件:config.ini配置⽂件中按照功能模块分为 risk 、rule 、term ;其下的url地址分别代表该模块下某个功能点的url[risk];新建风险url0 = ;新建风险⽬录、导⼊风险模板url1 = xxxx[rule];新建制度⽬录url1 = xxxxx;制度审批任务模板url2 = xxxxxxx[term];新建术语url1 = xxxxxx;新建术语⽬录url2 = xxxxxx2、读取配置⽂件:readConf.py 以下是封装好的读取配置⽂件的⽅法import configparserimport osclass ReadConf():def__init__(self):curpath = os.path.dirname(os.path.relpath(__file__)) #获取配置⽂件路径cfgpath = os.path.join(curpath, "config.ini")# 创建管理对象self.conf = configparser.ConfigParser()# 读ini⽂件self.conf.read(cfgpath, encoding="utf-8")def readConf(self,param):#获取所有的section# sections = self.conf.sections()# print(sections)#获取某个sections中的所有值,将其转化为字典items = dict(self.conf.items(param))return itemsif__name__ == '__main__':test = ReadConf()t = test.readConf("risk") #传⼊sections的值print('我取某个sections下所有值 ',t)print(t['url1'])3、⽤例编写优化前代码:import unittestfrom pages.risk.createRisk import CreateRiskfrom selenium import webdriverimport timebase_url = "xxxx"class TestCreateRisk(unittest.TestCase):@classmethoddef setUpClass(cls):cls.driver = webdriver.Chrome()cls.driver.maximize_window()cls.risk = CreateRisk(cls.driver)def setUp(self):self.driver.get(base_url)def tearDown(self):self.driver.delete_all_cookies()@classmethoddef tearDownClass(cls):cls.driver.quit()def test_create_risk(self):'''新建风险点'''random = self.risk.get_random_chinese()self.risk.createRisk(random)time.sleep(3)if__name__ == '__main__':unittest.main()优化后代码:import unittestfrom pages.risk.createRisk import CreateRiskfrom selenium import webdriverfrom common.readConf import ReadConfimport timeclass TestCreateRisk(unittest.TestCase):@classmethoddef setUpClass(cls):cls.driver = webdriver.Chrome()cls.driver.maximize_window()cls.risk = CreateRisk(cls.driver)# 读取配置⽂件,传⼊sections值,cls.url = ReadConf()cls.standard_url = cls.url.readConf('risk') #这⾥传⼊risk模块# 获取配置⽂件中的urlcls.base_url = cls.standard_url['url0'] #这⾥传⼊risk模块中新建风险的url print(cls.base_url)def setUp(self):self.driver.get(self.base_url)def tearDown(self):self.driver.delete_all_cookies()@classmethoddef tearDownClass(cls):cls.driver.quit()def test_create_risk(self):'''新建风险点'''random = self.risk.get_random_chinese()self.risk.createRisk(random)time.sleep(3)if__name__ == '__main__':unittest.main()经过修改后,每次更新url地址,只需在配置⽂件中修改就好了,是不是⽅便多了~~。
net 6 ini文件的读写方法在.NET 6中,INI文件可以通过使用``命名空间中的类进行读写。
以下是一个简单的示例,演示如何读取和写入INI文件:首先,确保你的项目已经安装了``和``这两个NuGet包。
1. 读取INI文件:```csharpusing ;using ;class Program{static void Main(string[] args){IConfiguration config = new ConfigurationBuilder().AddIniFile("") // 指定INI文件路径.Build();string settingValue = config["section:key"]; // 读取section下的key值(settingValue);}}```在上面的代码中,我们使用了`ConfigurationBuilder`来构建配置,并添加了INI文件。
然后,通过键(section:key)来获取配置值。
2. 写入INI文件:为了写入INI文件,你需要先创建一个`IConfiguration`实例,然后使用`Save`方法保存配置。
这里有一个示例:```csharpusing ;using ;using ;using ;class Program{static void Main(string[] args){IConfiguration config = new ConfigurationBuilder().AddIniFile("", optional: true) // 指定INI文件路径,可选参数默认为false,设置为true则不会抛出异常当文件不存在时。
.Build();("", optional: true); // 可以同时从多个源加载配置,这里再添加一个JSON配置文件。
VC中用函数读写ini文件的方法原文地址/ncre2/cpp/jiqiao/20100705/082550499.htmlini文件(Initialization file),这种类型的文件中通常存放的是一个程序的初始化信息。
ini文件由若干个节(Section)组成,每个Section由若干键(Key)组成,每个Key可以赋相应的值。
读写ini文件实际上就是读写某个的Section中相应的Key的值,而这只要借助几个函数即可完成。
一、向ini文件中写入信息的函数1. 把信息写入系统的win.ini文件BOOL WriteProfileString(LPCTSTR lpAppName, // 节的名字,是一个以0结束的字符串LPCTSTR lpKeyName, // 键的名字,是一个以0结束的字符串。
若为NULL,则删除整个节LPCTSTR lpString // 键的值,是一个以0结束的字符串。
若为NULL,则删除对应的键)2. 把信息写入自己定义的.ini文件BOOL WritePrivateProfileString(LPCTSTR lpAppName, // 同上LPCTSTR lpKeyName, // 同上LPCTSTR lpString, // 同上LPCTSTR lpFileName // 要写入的文件的文件名。
若该ini文件与程序在同一个目录下,// 也可使用相对路径,否则需要给出绝度路径。
)如:::WriteProfileString("Test", "id", "xym");// 在win.ini中创建一个Test节,并在该节中创建一个键id,其值为xym::WritePrivateProfileString("Test", "id", "xym", "d:\\vc\\Ex1\\ex1.ini");// 在Ex1目录下的ex1.ini中创建一个Test节,并在该节中创建一个键id,其值为xym// 若Ex1.ini文件与读写该文件的程序在同一个目录下,则上面语句也可写为:::WritePrivateProfileString("Test", "id", "xym", ".\\ex1.ini");需要注意的是,C系列的语言中,转义字符“\\”表示反斜线“\”。
ini文件写法摘要:一、ini文件的概述1.ini文件的概念2.ini文件的作用3.ini文件的组成部分二、ini文件的写法1.创建ini文件的基本结构2.设置键值对3.注释的使用4.格式规范三、ini文件的读取1.读取ini文件的方法2.解析ini文件的内容3.获取和处理键值对四、ini文件的常见应用场景1.配置文件的存储和读取2.应用程序的参数设置3.开发中的数据存储和读取正文:ini文件是一种配置文件格式,常用于存储和读取应用程序的配置信息。
它的组成部分主要包括节(section)、键(key)和值(value)。
在ini文件中,节用方括号[]括起来,键和值用等号=连接。
此外,ini文件允许使用注释,注释以分号;开始,直到行末尾。
ini文件的写法比较简单。
首先,需要创建一个基本的文件结构,包括文件名和扩展名.ini。
然后,根据需要设置键值对,例如:```[section1]key1=value1key2=value2[section2]key3=value3```在ini文件中,可以使用注释来对配置信息进行说明。
注释以分号;开始,直到行末尾,例如:```; 这是一个注释[section1]key1=value1key2=value2```要读取ini文件,可以使用编程语言提供的相应方法。
例如,在Python 中,可以使用configparser库来实现ini文件的读取。
首先,需要安装configparser库,然后按照以下步骤进行操作:```pythonimport configparser# 创建一个ConfigParser对象config = configparser.ConfigParser()# 读取ini文件config.read("example.ini")# 获取和处理键值对print(config.get("section1", "key1")) # 输出:value1print(config.getint("section1", "key2")) # 输出:2```ini文件在实际应用中有很多场景,如存储和读取配置信息、设置应用程序参数、开发过程中的数据存储和读取等。
一个手工读写INI文件的类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型数据到变量lCfgData.GetLongData("timeout",l);//读取字符串型数据到变量strCfgData.GetStrData("default",str);//设置当前组CfgData.SetGroup("operating systems");//读取字符串型数据到变量strCfgData.GetStrData("multi(0)disk(0)rdisk(0)partition(2)\\WINNT",str);//读取字符串型数据到变量strCfgData.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 > 1000class 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_FILEstatic 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;}//得到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);}}//将配置数据保存到文件/*参数: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;}。