大多数的应用程序都有需要配置的参数,配置参数的保存有多种方法,比如采用数据库保存、二进制文件保存、格式化的文本文件保存,各有优缺点,对于一般小的安全性要求不高应用程序,推荐采用格式化文本文件保存方式,这样可以节约编辑修改的界面编程,使用记事本程序编辑即可。
早期的windows就是采用的INI格式文本文件。现在很多应用程序包括大型的软件也还在采用格式化文本文件保存配置参数,比如Bentely MicroStation GIS平台GEOGRAPHICS8.0。
本文给出的就是利用VC来读取和分析配置文本文件,这是笔者这消防监控系统远程终端软件使用的方法。同时给出一个C++类来封装配置文本文件的读取分析。
下面是我采用的配置文件的例子,包含单个参数定义,表格参数定义,注释:
// 协议名称: TL
// 工程: SQ
// 配置人: JY
#DEFINE_BEGIN //以下为常量定义
//通信参数
@COM_PORT \\.\COM1 //COM口
@COM_BAUDRATE 1200 //波特率
@COM_BITSIZE 8 //数据位 number of bits/byte, 4-8
@COM_STOPBIT 0 // 0,1,2 对应 1, 1.5, 2
@COM_PARITY 0 //0-4对应no,odd,even,mark,space
@STATIONNO 0 //终端号
@TCPIP_SERVERIP 192.168.0.10 //服务器IP地址
@TCPIP_PORTNO 3024 //端口
#DEFINE_END
#TABLE_BEGIN //表格
//编号 识别字符串
//例子如下
0 Ion Detector, ALU1, L1S43 //测量台2#离子烟感探测器 报警
1 Thermal Det, ALU1, L1S39 //值班室温感探测器报警
#TABLE_END
语法解释:
// 单行注释
#DEFINE_BEGIN 单个参数定义的开始标记
#DEFINE_END 单个参数定义的结束标记
#TABLE_BEGIN 表格参数开始标记
#TABLE_END 表格参数结束标记
单个参数的配置:
每个参数一行:以空格、TAB制表符作为分隔,注释可选,每行结束后有Enter键换行。
表格参数配置:第一列为数字编号,作为ID用,第一列和第二列之间采用空格、TAB制表符作为分隔,其他列之间采用','逗号、空格、TAB制表符分隔,因此从第二列起,字符串中间夹的空格是有效字符。比如上面例子中的第一行解释如下:
"0","Ion Detector","ALU1","L1S43"
同样,表格参数也是每行有Enter键换行。
下面给出一个C++类来完成这个格式的文本配置读取和分析。
规模:
文本文件的大小:<48kbytes
单个参数定义个数:不限
表格参数定义: 100行 X 4列
这些规模大小可以修改下面的宏定义来满足你的需要
#define TABLE_MAXROW 100
#define TABLE_MAXCOL 5 //含索引ID列
typedef struct{
int nID;
char s[TABLE_MAXCOL-1][64];
}TAG_TABLEREC,*LPTABLEREC;
class CDataTxt
{
public:
CDataTxt();
~CDataTxt();
CString m_szPath;//配置文件全路经名
BOOL Read();//读入文件
BOOL GetDefine(LPCTSTR lpszName,CString &szVal);//获取定义
//{{TABLE
TAG_TABLEREC m_Table[TABLE_MAXROW];
int m_nRows;
//}}
private:
char m_cbuf[1024*48];
int m_nBufSize;//=1024*48;
int m_nDataSize;
CString m_szDefine;//定义段
int m_nDefineLen;
CString m_szTable;//表格段
int m_nTableLen;
void DelNote();//去掉注释
void FormatTable(void);//规格化表格
};
CDataTxt::CDataTxt()
{
int i;
m_szPath="SQTL.txt";
m_nBufSize=1024*48;
m_nDataSize=0;
m_nDefineLen=0;
m_nTableLen=0;
for(i=0;i<m_nBufSize;i++)
m_cbuf =0;
ZeroMemory(&m_Table,sizeof(m_Table));
m_nRows=0;
}
CDataTxt::~CDataTxt()
{
}
BOOL CDataTxt::Read()
{
CFile fl;
if(!fl.Open(m_szPath,CFile::modeRead|CFile::typeBinary))
return FALSE;
DWORD dwl=fl.GetLength();
if(dwl > (DWORD)m_nBufSize)
dwl=(DWORD)m_nBufSize;
m_nDataSize=(int)(fl.Read(m_cbuf,dwl));
fl.Close();
DelNote();//去掉注释
return TRUE;
}
void CDataTxt::DelNote()//去掉注释,分成定义段和表格段
{
CString szt="";
char cc,ccp=0;
int i;
for(i=0;i<m_nDataSize;i++)
{
cc=m_cbuf;
if(cc != '/'){ szt+=cc;ccp=cc; }
else//cc=='/'
{
if(i<m_nDataSize)
{
if(m_cbuf[i+1]=='/')//注释开始
{
while((i<m_nDataSize)&&(m_cbuf!=0x0d)) i++;
if(m_cbuf==0x0d) i--;
ccp=0;
}
else{szt+=cc; ccp=cc; }
}
}
}
m_nDataSize=szt.GetLength();
sprintf(m_cbuf,"%s",szt);
int ns=szt.Find("#DEFINE_BEGIN",0);
int ne=szt.Find("#DEFINE_END",0);
if((ns==-1)||(ne==-1)) return;
ns+=13;
m_szDefine="";
for(i=ns;i<ne;i++) m_szDefine+=szt;
m_nDefineLen=m_szDefine.GetLength();
ns=szt.Find("#TABLE_BEGIN",0);
ne=szt.Find("#TABLE_END",0);
ns+=12;
if((ns==-1)||(ne==-1)) return;
m_szTable="";
for(i=ns;i<ne;i++) m_szTable+=szt;
m_nTableLen=m_szTable.GetLength();
FormatTable();//规格化表格
}
BOOL CDataTxt::GetDefine(LPCTSTR lpszName,CString &szVal)//获取定义
{
CString szName=lpszName;
if(szName.IsEmpty()) return FALSE;
int nLen=szName.GetLength();
int ns=m_szDefine.Find(lpszName,0);
if(ns==-1) return FALSE;
szVal="";
int i=ns+nLen;
BOOL bStartCopy=FALSE;
char cc;
while(i<m_nDefineLen)
{
cc=m_szDefine;
if((cc!=0x0D)&&(cc!=0x0A)&&(cc!='\t')&&(cc!=0x20))
{
if(bStartCopy==FALSE) bStartCopy=TRUE;
szVal+=m_szDefine;
}
else{if(bStartCopy) break;} i++;
}
return TRUE;
}
void CDataTxt::FormatTable()//规格化表格
{
int i=0;
char cc;
int nRow=0;
CString szLine="",szID="",szVal="",szCol="";
int nCol=0;
while(i<m_nTableLen)
{
cc=m_szTable;
if((cc==0x0A)||(cc=='\t')) cc=0x20;
if(cc==0X0D)//处理一行
{
szLine.TrimLeft(); szLine.TrimRight();
if(!szLine.IsEmpty())
{
int nl=szLine.GetLength();
int j;
char c;
szID="";
for(j=0;j<nl;j++)//取szID
{
c=szLine[j];
if(c==0x20)
break;
szID+=c;
}
m_Table[nRow].nID=atoi(szID);
BOOL bStart;
bStart=FALSE;
szVal="";
while(j<nl)//取szCols
{
c=szLine[j];
if((bStart==FALSE)&&(c==0x20)) j++;
else{bStart=TRUE;szVal+=c;j++;}
}
szVal.TrimLeft();szVal.TrimRight();
nCol=0; nl=szVal.GetLength();
j=0;szCol="";
while(j<nl)
{
c=szVal[j];
if(c==',')
{
if(szCol.IsEmpty()) break;
else
{
if(nCol < TABLE_MAXCOL-1)
{
if(szCol.GetLength() <64)
sprintf(&(m_Table[nRow].s[nCol][0]),"%s",szCol);
nCol++; TRACE("szCol=%s\n",szCol);
}
}
szCol="";
}
else szCol+=c;
j++;
}
if(!szCol.IsEmpty())
{
if(nCol < TABLE_MAXCOL-1)
{
if(szCol.GetLength() <64)
sprintf(m_Table[nRow].s[nCol],"%s",szCol);
nCol++; TRACE("szCol=%s\n",szCol);
}
}
if(nCol>0)
nRow++;
if(m_nRows >=TABLE_MAXROW)
{
m_nRows=nRow;
return;
}
szLine="";
}
}
else szLine+=cc;
i++;
}
m_nRows=nRow;
}
void test()
{
CDataTxt dt;
dt.m_szPath="c:\\sqtl.txt";
dt.Read();
CString szVal,szMsg;
if(dt.GetDefine("@COM_PORT",szVal)){TRACE("@COM_PORT=%s\n",szVal);}
if(dt.GetDefine("@COM_BAUDRATE",szVal)){TRACE("@COM_BAUDRATE=%s\n",szVal);}
int i;
for(i=0;i<dt.m_nRows;i++)
{
TRACE("Row=%d,ID=%d,s[0]=%s,sz[1]=%s,s[2]=%s,s[3]=%s\n",
i,
dt.m_Table.nID,
&(dt.m_Table.s[0][0]),
&(dt.m_Table.s[1][0]),
&(dt.m_Table.s[2][0]),
&(dt.m_Table.s[3][0]));
}
}
文件读取:
void CShotdetect::WritetoText(int p1, LONGLONG p2)
{
CString str;
str = "c:\\文本文件.txt";
CFile file;
file.Open(str,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate);
char ch_str1[30];
char ch_str2[20];
_itoa(p1,ch_str1,10);
strcat(ch_str1,",");
_itoa(p2,ch_str2,10);
strcat(ch_str1,ch_str2);
strcat(ch_str1,"\n");
int length = 0;
for(int i = 0;i<30;i++)
{
if(ch_str1!='\0')
length++;
else
break;
}
file.SeekToEnd();
file.Write(ch_str1,length);
file.Close();
早期的windows就是采用的INI格式文本文件。现在很多应用程序包括大型的软件也还在采用格式化文本文件保存配置参数,比如Bentely MicroStation GIS平台GEOGRAPHICS8.0。
本文给出的就是利用VC来读取和分析配置文本文件,这是笔者这消防监控系统远程终端软件使用的方法。同时给出一个C++类来封装配置文本文件的读取分析。
下面是我采用的配置文件的例子,包含单个参数定义,表格参数定义,注释:
// 协议名称: TL
// 工程: SQ
// 配置人: JY
#DEFINE_BEGIN //以下为常量定义
//通信参数
@COM_PORT \\.\COM1 //COM口
@COM_BAUDRATE 1200 //波特率
@COM_BITSIZE 8 //数据位 number of bits/byte, 4-8
@COM_STOPBIT 0 // 0,1,2 对应 1, 1.5, 2
@COM_PARITY 0 //0-4对应no,odd,even,mark,space
@STATIONNO 0 //终端号
@TCPIP_SERVERIP 192.168.0.10 //服务器IP地址
@TCPIP_PORTNO 3024 //端口
#DEFINE_END
#TABLE_BEGIN //表格
//编号 识别字符串
//例子如下
0 Ion Detector, ALU1, L1S43 //测量台2#离子烟感探测器 报警
1 Thermal Det, ALU1, L1S39 //值班室温感探测器报警
#TABLE_END
语法解释:
// 单行注释
#DEFINE_BEGIN 单个参数定义的开始标记
#DEFINE_END 单个参数定义的结束标记
#TABLE_BEGIN 表格参数开始标记
#TABLE_END 表格参数结束标记
单个参数的配置:
每个参数一行:以空格、TAB制表符作为分隔,注释可选,每行结束后有Enter键换行。
表格参数配置:第一列为数字编号,作为ID用,第一列和第二列之间采用空格、TAB制表符作为分隔,其他列之间采用','逗号、空格、TAB制表符分隔,因此从第二列起,字符串中间夹的空格是有效字符。比如上面例子中的第一行解释如下:
"0","Ion Detector","ALU1","L1S43"
同样,表格参数也是每行有Enter键换行。
下面给出一个C++类来完成这个格式的文本配置读取和分析。
规模:
文本文件的大小:<48kbytes
单个参数定义个数:不限
表格参数定义: 100行 X 4列
这些规模大小可以修改下面的宏定义来满足你的需要
#define TABLE_MAXROW 100
#define TABLE_MAXCOL 5 //含索引ID列
typedef struct{
int nID;
char s[TABLE_MAXCOL-1][64];
}TAG_TABLEREC,*LPTABLEREC;
class CDataTxt
{
public:
CDataTxt();
~CDataTxt();
CString m_szPath;//配置文件全路经名
BOOL Read();//读入文件
BOOL GetDefine(LPCTSTR lpszName,CString &szVal);//获取定义
//{{TABLE
TAG_TABLEREC m_Table[TABLE_MAXROW];
int m_nRows;
//}}
private:
char m_cbuf[1024*48];
int m_nBufSize;//=1024*48;
int m_nDataSize;
CString m_szDefine;//定义段
int m_nDefineLen;
CString m_szTable;//表格段
int m_nTableLen;
void DelNote();//去掉注释
void FormatTable(void);//规格化表格
};
CDataTxt::CDataTxt()
{
int i;
m_szPath="SQTL.txt";
m_nBufSize=1024*48;
m_nDataSize=0;
m_nDefineLen=0;
m_nTableLen=0;
for(i=0;i<m_nBufSize;i++)
m_cbuf =0;
ZeroMemory(&m_Table,sizeof(m_Table));
m_nRows=0;
}
CDataTxt::~CDataTxt()
{
}
BOOL CDataTxt::Read()
{
CFile fl;
if(!fl.Open(m_szPath,CFile::modeRead|CFile::typeBinary))
return FALSE;
DWORD dwl=fl.GetLength();
if(dwl > (DWORD)m_nBufSize)
dwl=(DWORD)m_nBufSize;
m_nDataSize=(int)(fl.Read(m_cbuf,dwl));
fl.Close();
DelNote();//去掉注释
return TRUE;
}
void CDataTxt::DelNote()//去掉注释,分成定义段和表格段
{
CString szt="";
char cc,ccp=0;
int i;
for(i=0;i<m_nDataSize;i++)
{
cc=m_cbuf;
if(cc != '/'){ szt+=cc;ccp=cc; }
else//cc=='/'
{
if(i<m_nDataSize)
{
if(m_cbuf[i+1]=='/')//注释开始
{
while((i<m_nDataSize)&&(m_cbuf!=0x0d)) i++;
if(m_cbuf==0x0d) i--;
ccp=0;
}
else{szt+=cc; ccp=cc; }
}
}
}
m_nDataSize=szt.GetLength();
sprintf(m_cbuf,"%s",szt);
int ns=szt.Find("#DEFINE_BEGIN",0);
int ne=szt.Find("#DEFINE_END",0);
if((ns==-1)||(ne==-1)) return;
ns+=13;
m_szDefine="";
for(i=ns;i<ne;i++) m_szDefine+=szt;
m_nDefineLen=m_szDefine.GetLength();
ns=szt.Find("#TABLE_BEGIN",0);
ne=szt.Find("#TABLE_END",0);
ns+=12;
if((ns==-1)||(ne==-1)) return;
m_szTable="";
for(i=ns;i<ne;i++) m_szTable+=szt;
m_nTableLen=m_szTable.GetLength();
FormatTable();//规格化表格
}
BOOL CDataTxt::GetDefine(LPCTSTR lpszName,CString &szVal)//获取定义
{
CString szName=lpszName;
if(szName.IsEmpty()) return FALSE;
int nLen=szName.GetLength();
int ns=m_szDefine.Find(lpszName,0);
if(ns==-1) return FALSE;
szVal="";
int i=ns+nLen;
BOOL bStartCopy=FALSE;
char cc;
while(i<m_nDefineLen)
{
cc=m_szDefine;
if((cc!=0x0D)&&(cc!=0x0A)&&(cc!='\t')&&(cc!=0x20))
{
if(bStartCopy==FALSE) bStartCopy=TRUE;
szVal+=m_szDefine;
}
else{if(bStartCopy) break;} i++;
}
return TRUE;
}
void CDataTxt::FormatTable()//规格化表格
{
int i=0;
char cc;
int nRow=0;
CString szLine="",szID="",szVal="",szCol="";
int nCol=0;
while(i<m_nTableLen)
{
cc=m_szTable;
if((cc==0x0A)||(cc=='\t')) cc=0x20;
if(cc==0X0D)//处理一行
{
szLine.TrimLeft(); szLine.TrimRight();
if(!szLine.IsEmpty())
{
int nl=szLine.GetLength();
int j;
char c;
szID="";
for(j=0;j<nl;j++)//取szID
{
c=szLine[j];
if(c==0x20)
break;
szID+=c;
}
m_Table[nRow].nID=atoi(szID);
BOOL bStart;
bStart=FALSE;
szVal="";
while(j<nl)//取szCols
{
c=szLine[j];
if((bStart==FALSE)&&(c==0x20)) j++;
else{bStart=TRUE;szVal+=c;j++;}
}
szVal.TrimLeft();szVal.TrimRight();
nCol=0; nl=szVal.GetLength();
j=0;szCol="";
while(j<nl)
{
c=szVal[j];
if(c==',')
{
if(szCol.IsEmpty()) break;
else
{
if(nCol < TABLE_MAXCOL-1)
{
if(szCol.GetLength() <64)
sprintf(&(m_Table[nRow].s[nCol][0]),"%s",szCol);
nCol++; TRACE("szCol=%s\n",szCol);
}
}
szCol="";
}
else szCol+=c;
j++;
}
if(!szCol.IsEmpty())
{
if(nCol < TABLE_MAXCOL-1)
{
if(szCol.GetLength() <64)
sprintf(m_Table[nRow].s[nCol],"%s",szCol);
nCol++; TRACE("szCol=%s\n",szCol);
}
}
if(nCol>0)
nRow++;
if(m_nRows >=TABLE_MAXROW)
{
m_nRows=nRow;
return;
}
szLine="";
}
}
else szLine+=cc;
i++;
}
m_nRows=nRow;
}
void test()
{
CDataTxt dt;
dt.m_szPath="c:\\sqtl.txt";
dt.Read();
CString szVal,szMsg;
if(dt.GetDefine("@COM_PORT",szVal)){TRACE("@COM_PORT=%s\n",szVal);}
if(dt.GetDefine("@COM_BAUDRATE",szVal)){TRACE("@COM_BAUDRATE=%s\n",szVal);}
int i;
for(i=0;i<dt.m_nRows;i++)
{
TRACE("Row=%d,ID=%d,s[0]=%s,sz[1]=%s,s[2]=%s,s[3]=%s\n",
i,
dt.m_Table.nID,
&(dt.m_Table.s[0][0]),
&(dt.m_Table.s[1][0]),
&(dt.m_Table.s[2][0]),
&(dt.m_Table.s[3][0]));
}
}
文件读取:
void CShotdetect::WritetoText(int p1, LONGLONG p2)
{
CString str;
str = "c:\\文本文件.txt";
CFile file;
file.Open(str,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate);
char ch_str1[30];
char ch_str2[20];
_itoa(p1,ch_str1,10);
strcat(ch_str1,",");
_itoa(p2,ch_str2,10);
strcat(ch_str1,ch_str2);
strcat(ch_str1,"\n");
int length = 0;
for(int i = 0;i<30;i++)
{
if(ch_str1!='\0')
length++;
else
break;
}
file.SeekToEnd();
file.Write(ch_str1,length);
file.Close();
本文转自 life0 51CTO博客,原文链接:http://blog.51cto.com/life0/12412,如需转载请自行联系原作者