介绍
继前段时间写了刚过系列文章后收到很多热心的读者给我的留言和邮件,中间有很多技术同行对我的错误的指正,还有很多读者对我的支持.本来应该一次写上的东西结果由于公司的安排或者时间等因素到现在都没有完全写上来.在后面的时间里我会尽快晚上其余部分内容,希望对各位相关方面寻求帮助或者各位初学者在VC的道路上面有一定的帮助作用.
作为中小型电站系统的开发,由于涉及到的点和数据库的操作不是很繁琐,我们基本上可以放弃SQLSERVER等大型数据库模式,采用ACCESS能够实现,如果有要求网络功能的话我们也可以在中间加挂一个SOCKET通讯就可以实现了.
正文
电站监控系统中间对于历史数据的存储应该有严格的要求.电站监控系统很大一个特点就是实时性和安全性.其中对于很多的操作比如控制或者事故都需要进行历史数据的记录.由于在前面提到中小型电站系统我们可以采用ACCESS作为数据库的开发.历史数据我们可以采用存放于ACCESS数据库内部的一个专用表格里面,但是随着历史数据的增多会造成数据库容量的不断增大,这样对以后数据库历史资料的维护和系统的查询等工作带来影响,所以我推荐对于历史数据的存储如果条件可以我们可以采用文件存储的形式存储到硬盘或者其余存储介值上.
如果我们用CFILE对象进行操作都能够实现,在以前我看到过一个封装文件操作的一个类,觉得很方便应用于我们程序的开发,我对其中的部分功能进行了修改和功能的扩充,基本能满足我们存储的要求了,现在就如何应用进行简单的介绍.各位也可以根据我的修改方法对其中功能类进行相应的修改达到完成自己的功能
首先修改结构体数据
struct _DBRECORD
{
unsigned char strData[30];//用于记录日期,比如2005-08-12等类型
unsigned char strTime[30];//用于记录出现的具体时间,一般要求精确到毫秒,比如12:45:36:458
unsigned char strId[30]; //记录事件的标识ID
unsigned char strName[30];//记录时间的名称
unsigned char strDescribe[30];//记录时间的描述
};
修改的实现部分为:
CFileSet::CFileSet()
{
filename = _T("");
Status = FALSE;
position = 0;
length = 0;
unsigned char buff[1024];
memset(buff,0,1024);
::GetTempPath(1024,(char *)&buff);
temppath.Format("%s",buff);
memset(&record,0,sizeof(record));
strData = _T("");
strTime = _T("");
strId = _T("");
strName = _T("");
strDes = _T("");
}
BOOL CFileSet::Open(CString m_strFile)
{
filename = m_strFile;
Status = file.Open(filename,CFile::modeCreate|CFile::modeReadWrite|CFile::modeNoTruncate);
/* if (Status)
{
length = (file.GetLength())/recordsize;
// file.SeekToBegin();
// if (length>0)
// Read();
}*/
return Status;
}
void CFileSet::UpdateData(BOOL bUpdate)
{
if (bUpdate)
{
strcpy((char *)record.strData,LPCTSTR(strData));
strcpy((char *)record.strTime,LPCTSTR(strTime));
strcpy((char *)record.strId,LPCTSTR(strId));
strcpy((char *)record.strName,LPCTSTR(strName));
strcpy((char *)record.strDescribe,LPCTSTR(strDes));
}
else
{
strData.Format("%s",record.strData);
strTime.Format("%s",record.strTime);
strId.Format("%s",record.strId);
strName.Format("%s",record.strName);
strDes.Format("%s",record.strDescribe);
}
}
调用方法可以如下:
我们进行历史资料存储的时候一般会用程序在硬盘的某个路径下面创建一个文件夹,然后将要存储的文件按照某种命名进行该文件夹下的存储就可以了.我采用的是用户的硬盘的数据备份盘创建一个"历史数据文件夹",然后将每天形成的信息包含事故记录或者操作票记录以当天日期为文件名进行相应的处理进行存储.下面是我的调用方法:
首先将FileSet.cpp和FileSet.h加入工程
然后定义FileSet类对象
CFileSet m_FileSet;
编写一个函数操作接口,然后每次出现事故或者需要进行数据存储的时候调用该函数
void CYbkDemoView::WriteHisMsgToFile(CString szData, CString szTime, CString szId, CString szName, CString szDes,BOOL bAlarm)
//写报警文件
{
CString sPath,szFileName;
CTime t = CTime::GetCurrentTime();
m_FileSet.strData = szData;
m_FileSet.strTime = szTime;
m_FileSet.strId = szId;
m_FileSet.strName = szName;
m_FileSet.strDes = szDes+@#\r@#+@#\n@#;
int nTempPos=t.GetHour()*60+t.GetMinute();
sPath.Format("d:\\历史数据文件夹\\%.4d年%.2d月%.2d日",
t.GetYear(),t.GetMonth(),t.GetDay()); ::CreateDirectory(sPath,NULL);
if(bAlarm)//写报警文件
szFileName.Format(sPath+"\\Alarm.txt");
else//写操作文件
szFileName.Format(sPath+"\\ColDev.txt");
m_FileSet.Open(szFileName);
m_FileSet.AddNew();
m_FileSet.Close();
}
我们可以通过调用上面的函数就可以简单的实现数据的写入了.
比如写入操作票:WriteHisMsgToFile("2004-12-25","12:12:12:125","0001","李主任","对1号断路器进行分闸操作",FALSE);
写入事故报警:WriteHisMsgToFile("2004-12-25","12:12:12:125","K234","1#发电机变压器组","重瓦斯动作",TRUE);
历史数据的存储当然需要用到数据的读取,中间我们也可以采用封装的方法进行,下面是我写的一个基本用法.,根据用户输入的追忆日期进行查询,查询条件可以根据情况不同进行更改
BOOL C****View::ReadHisMsgFromFile(CString szYear, CString szMonth, CString szDay)
{
CString sPath,szFileName;
sPath = "d:\\历史数据文件夹\\"+szYear+"年"+szMonth+"月"+szDay+"日";
CFileFind fFind;
if(!fFind.FindFile(sPath))
{
::AfxMessageBox("没有找到历史记录!");
return FALSE;
}
///////////读事故
CString MsData,MsTime,MsId,MsName,MsDes;
szFileName.Format("\\Alarm.txt");
this->m_FileSet.Open(sPath+szFileName);
//Reset buffer value
int t=m_FileSet.file.GetLength();
nLen=t/(sizeof(m_FileSet.record));
for(int i=0;i
this->m_FileSet.file.Read(&m_FileSet.record,sizeof(m_FileSet.record));
MsData = m_FileSet.record.strData;
MsTime = m_FileSet.record.strTime;
MsId = m_FileSet.record.strId;
MsName = m_FileSet.record.strName;
MsDes = m_FileSet.record.strDescribe;
//这里可以进行相应的数据读出处理工作
}
this->m_FileSet.Close();
///////////读操作记录
szFileName.Format("\\ColDev.qigao");
this->m_FileSet.Open(sPath+szFileName);
//Reset buffer value
t=m_FileSet.file.GetLength();
nLen=t/(sizeof(m_FileSet.record));
for(i=0;i
this->m_FileSet.file.Read(&m_FileSet.record,sizeof(m_FileSet.record));
MsData = m_FileSet.record.strData;
MsTime = m_FileSet.record.strTime;
MsId = m_FileSet.record.strId;
MsName = m_FileSet.record.strName;
MsDes = m_FileSet.record.strDescribe;
//这里可以进行相应的数据读出处理工作
}
this->m_FileSet.Close();
db.Close();
return TRUE;
}
调用方法就很简单了,比如ReadHisMsgFromFile(2004,12,12);
延伸阅读
文章来源于领测软件测试网 https://www.ltesting.net/