1.VC输入输出流与MAT文件
VisualC++中数据的输入输出多采用串行化方式进行。串行化是通过MFC提供的类Carchive对C++运算符<<和>>重载后进行的。一般情况下,使用CArchive对对象进行读操作的过程如下:
void CProjectNameDoc::Serialize(CArchive& ar)
{ if(ar.IsStoring()) ////////////////写入方式
{
ar >> obj1>>obj2>>obj3...>>objn; ////按顺序读取数据操作
}
else ////////////////读取方式
{
ar << obj1<<obj2<<obj3...<<objn; ////按顺序写入数据操作
}
COleServerDoc::Serialize(ar);// 调用ColeServerDoc类实现操作符重载
}
MAT文件是MATLAB中数据输入输出的基本方法。在VisualC++中一般的MAT文件读取操作为:
mxArray *Read_mxArray(MATFile *pmat,const char *VariableName)
{ mxArray *out; CString str;
out=matGetVariable(pmat, VariableName);
str.Format(“读取变量:%s错误,返回”, VariableName); ////定义提示信息
if(out==(mxArray *)NULL){ AfxMessageBox(str); return 0; }
return(out);////////////////////////////返回所读取的变量
}
在VisualC++中一般的MAT文件写入操作为:
void Write_mxArray(MATFile *pmat, char *VariableName,mxArray *Variable)
{ CString str;
str.Format(“写入变量:%s错误,返回”, VariableName); ////定义提示信息
if((matPutVariable(pmat,VariableName,Variable))!=0){AfxMessageBox(str);}
}
2.VC与MAT文件示例-VCmat1
从上述两种文件格式的输入输出过程可知,只要把mxArray类型的数据Variable与obj对应起来,并进行相应的数据类型转换,就可以实现MAT文件与Cfile文件间转换。由于VisualC++对操作符<<和>>重载后,obj对象可以是由Cobject及其派生类对象,其数据类型远比mxArray对象复杂。因此,这种转换方式并不能将所有的CFile文件转换为MAT文件。此外,在VisualC++中输入输出MAT文件,若仍在MATLAB中使用mex实现,则与第7章用C编写MAT程序十分相似,若要在VisualC++的IDE中编译,则需进行必要的环境配置。本节以一个简单的例子“VCmat1”工程来说明简单的CFile文件在VisualC++中转换为MAT文件的实现。
(1) VisualC++工程创建
启动VisualC++并单击File->New,打开Project对话框来创建各种VC工程,选取MFC Appwizard(exe)。在loctation编辑框中输入欲创建工程的保存路径,在Project name编辑框中输入工程名如“VCmat1”,单击OK进入下一步工程设置对话框,选中single document,单击Finish完成VCmat1工程创建。
(2)添加响应函数
在ResourceView中打开菜单IDR_MAINFRAME,按图1-5和表1-1添加菜单项和响应函数。
图1-5 VCmat1工程菜单项
表1-1 VCmat1工程菜单项属性与响应函数
| 菜单项 | ID | 响应函数 |
|---|---|---|
| SaveAsMATFile | ID_Menu_SaveAsMATFile | void CVCmat1Doc::OnMenuSaveAsMATFile() |
| InputFromMATFile | ID_Menu_InPutFromMAT | void CVCmat1Doc::OnMenuInPutFromMAT() |
| MATFileData | ID_Menu_MATFileData | void CVCmat1View::OnMenuMATFileData() |
| CFileData | ID_Menu_CFileData | void CVCmat1View::OnMenuCFileData() |
(3)环境配置
•设定头文件和库文件路径
菜单Tools->Options->Directories
Include files:添加%MATLAB7%extern\include
Library files:添加%MATLAB7%\Extern\Lib\Win32\Microsoft\Msvc60
•设置编译连接选项
菜单Project->Settings
Link->Object/Library modules: 添加libmat.lib libeng.lib libmx.lib libmex.lib
General->Microsoft Foundation Classes: Use MFC in a Static Library
(4)VCmat1中添加MAT文件读写操作
•在“VCmat1Doc.h”文件中添加头文件与mat文件读写操作函数申明:
//////////////////////////////////////头文件
#include "mex.h"
#include "mat.h"
/////////////////////////////////mat文件读写操作函数申明
public:
int m,n;
double c_x,*c_A,**c_AB;
mxArray *m_x,*m_A,*m_AB;
mxArray *Read_mxArray(MATFile *pmat,const char *VariableName);
void Write_mxArray(MATFile *pmat, char *VariableName,mxArray *Variable);
•在CVCmat1Doc()初始化文档时初始化数据
CVCmat1Doc::CVCmat1Doc()
{int i,j;
m=5; n=10;
c_x=10.0;//////////变量
c_A=new double[n]; //////////一维数组
for(i=0;i<n;i++)c_A[i]=(double)i;
c_AB=new double*[m];for(i=0;i<m;i++)c_AB[i]=new double[n];//二维数组
for(i=0;i<m;i++)for(j=0;j<n;j++)c_AB[i][j]=(double)(i*j+1);
m_x=mxCreateDoubleMATrix(1,1,mxREAL);
*mxGetPr(m_x)=c_x;
m_A=mxCreateDoubleMATrix(1,n,mxREAL);
for(i=0;i<n;i++)*(mxGetPr(m_A)+i)=c_A[i];
m_AB=mxCreateDoubleMATrix(m,n,mxREAL);
for(i=0;i<m;i++)for(j=0;j<n;j++){*(mxGetPr(m_AB)+j*m+i)=c_AB[i][j];}
}
当然,这些数据也可从其他函数中生成,或从文件中读入。
•在“VCmat1Doc.cpp”文件中实现MAT文件读写操作
将数据写入MAT文件代码:
void CVCmat1Doc::OnMenuSaveAsMATFile()
{
MATFile *pmat; CString str;
CFileDialog in(FALSE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
"MATLAB Data File(*.mat)|*.mat",NULL);
if(in.DoModal()==IDOK){str=in.GetPathName();
if((pmat=matOpen(str,"w"))==(MATFile *)NULL)////////以写入方式打开MAT文件
{AfxMessageBox("Can't open Out MATFile");exit(0);}
Write_mxArray(pmat,"m_x",m_x);////////////////////////////调用写入操作函数,依次写入数据
Write_mxArray(pmat,"m_A",m_A);
Write_mxArray(pmat,"m_AB",m_AB);
matClose(pmat); ////////////////////关闭mat文件
}
}
///////////////////从MAT文件读取数据代码:
void CVCmat1Doc::OnMenuInPutFromMAT()
{
MATFile *pmat; CString str;
CFileDialog in(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT
," MATLAB Data File(*.mat)|*.mat",NULL);
if(in.DoModal()==IDOK){str=in.GetPathName();
if((pmat=matOpen(str,"r"))==(MATFile *)NULL) ////////以读取方式打开MAT文件
{AfxMessageBox("Can't open Out MATFile");exit(-1);}
Read_mxArray(pmat,"m_x");////////////////////////////调用读取操作函数,依次读取数据
Read_mxArray(pmat,"m_A");
Read_mxArray(pmat,"m_AB");
matClose(pmat);////////////////////关闭mat文件
}
}
/////////////////////////////////////读取操作函数
mxArray *CVCmat1Doc::Read_mxArray(MATFile *pmat,const char *VariableName)
{ mxArray *out; CString str;
out=matGetVariable(pmat, VariableName);
str.Format("读取变量:%s错误,返回", VariableName); ////定义提示信息
if(out==(mxArray *)NULL){ AfxMessageBox(str); return 0; }
return(out);////////////////////////////返回所读取的变量
}
////////////////////////////////////写入操作函数
void CVCmat1Doc::Write_mxArray(MATFile *pmat, char *VariableName,mxArray *Variable)
{ CString str;
str.Format("写入变量:%s错误,返回", VariableName); ////定义提示信息
if((matPutVariable(pmat,VariableName,Variable))!=0){AfxMessageBox(str);}
}
•在VCmat1View窗口中显示从MAT文件中读取的数据
void CVCmat1View::OnMenuMATFileData()
{ Invalidate(TRUE);//////////////////////重绘窗口
CVCmat1Doc* pDoc=GetDocument();////////取得Doc文档句柄
ASSERT_VALID(pDoc);
CPaintDC dc(this);////////////////////取得上下文设备
dc.SetBkMode(TRANSPARENT); /////设置字体
dc.SetTextColor(RGB(0,155,155));
LOGFONT logfont;
memset(&logfont,0,sizeof(logfont));
logfont.lfWeight=20;
logfont.lfHeight=20;
lstrcpy(logfont.lfFaceName,"黑体");
CFont nowFont;
nowFont.CreateFontIndirect(&logfont);
dc.SelectObject(&nowFont);
//////////////////////////将mat文件中取得的数据输出到view窗口中
CString str; double *pii; int i,j;
pii=mxGetPr(pDoc->m_x);
str.Format("Input m_x : %7.2f",*pii); dc.TextOut(10,10,str);
str.Format("Input m_A : "); dc.TextOut(10,10+logfont.lfHeight,str);
pii=mxGetPr(pDoc->m_A);
for(i=0;i<pDoc->n;i++)
{str.Format(" %7.2f",*(pii+i));
dc.TextOut(100+i*3*logfont.lfWeight,10+logfont.lfHeight,str);
}
str.Format("Input m_AB: "); dc.TextOut(10,10+2*logfont.lfHeight,str);
pii=mxGetPr(pDoc->m_AB);
for(i=0;i<pDoc->m;i++)for(j=0;j<pDoc->n;j++)
{str.Format(" %7.2f",*(pii+j*pDoc->m+i));
dc.TextOut(100+j*3*logfont.lfWeight,10+3*logfont.lfHeight+i*logfont.lfHeight,str);
}
}
•在VC串行化读写数据操作
void CVCmat1Doc::Serialize(CArchive& ar)
{int i,j;
if(ar.IsStoring())
{
ar>>c_x;
for(i=0;i<n;i++)ar>>c_A[i];
for(i=0;i<m;i++)for(j=0;j<n;j++)ar>>c_AB[i][j];
}
else
{
ar<<c_x;
for(i=0;i<n;i++)ar<<c_A[i];
for(i=0;i<m;i++)for(j=0;j<n;j++)ar<<c_AB[i][j];
}
}
•在VCmat1View窗口中显示串行化读取的数据
void CVCmat1View::OnMenuCFileData()
{
Invalidate(TRUE);//////////////////////重绘窗口
CVCmat1Doc* pDoc=GetDocument();////////取得Doc文档句柄
ASSERT_VALID(pDoc);
CPaintDC dc(this);////////////////////取得上下文设备
dc.SetBkMode(TRANSPARENT); /////设置字体
dc.SetTextColor(RGB(255,0,0));
LOGFONT logfont;
memset(&logfont,0,sizeof(logfont));
logfont.lfWeight=20;
logfont.lfHeight=20;
lstrcpy(logfont.lfFaceName,"隶书");
CFont nowFont;
nowFont.CreateFontIndirect(&logfont);
dc.SelectObject(&nowFont);
//////////////////////////将CFile文件中取得的数据输出到view窗口中
CString str; int i,j;
str.Format("Input c_x : %7.2f",pDoc->c_x); dc.TextOut(10,10,str);
str.Format("Input c_A : "); dc.TextOut(10,10+logfont.lfHeight,str);
for(i=0;i<pDoc->n;i++)
{str.Format(" %7.2f",pDoc->c_A[i]);
dc.TextOut(100+i*3*logfont.lfWeight,10+logfont.lfHeight,str);
}
str.Format("Input c_AB: "); dc.TextOut(10,10+2*logfont.lfHeight,str);
for(i=0;i<pDoc->m;i++)for(j=0;j<pDoc->n;j++)
{str.Format(" %7.2f",pDoc->c_AB[i][j]);
dc.TextOut(100+j*3*logfont.lfWeight,10+3*logfont.lfHeight+i*logfont.lfHeight,str);
}
}
在VisualC++中编译执行VCmat1工程,从MAT读取数据在View窗口中显示结果如图1-6,由串行化读取数据在View窗口中显示结果如图1-7。从中可知,VCmat1工程实现了MAT文件的读写操作。
图1-6 从MAT读取数据在View窗口中显示结果
图1-7 串行化读取数据在View窗口中显示结果