VC与MAT文件

1.VC输入输出流与MAT文件

VisualC++中数据的输入输出多采用串行化方式进行。串行化是通过MFC提供的类Carchive对C++运算符<<和>>重载后进行的。一般情况下,使用CArchive对对象进行读操作的过程如下:

code.vc
void CProjectNameDoc::Serialize(CArchive& ar)
{	if(ar.IsStoring()) ////////////////写入方式
	{
		ar >> obj1>>obj2>&gt;obj3...>>objn; ////按顺序读取数据操作
	}
	else  ////////////////读取方式
	{
		ar << obj1<<obj2<&lt;obj3...<<objn; ////按顺序写入数据操作
	}
	COleServerDoc::Serialize(ar);// 调用ColeServerDoc类实现操作符重载
}

MAT文件是MATLAB中数据输入输出的基本方法。在VisualC++中一般的MAT文件读取操作为:

code.vc
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文件写入操作为:

code.vc
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添加菜单项和响应函数。

Document Image

图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文件读写操作函数申明:

code.vc
//////////////////////////////////////头文件
#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()初始化文档时初始化数据

code.vc
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文件代码:

code.vc
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&quot;,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串行化读写数据操作

code.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窗口中显示串行化读取的数据

code.vc
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文件的读写操作。

Document Image

图1-6 从MAT读取数据在View窗口中显示结果

Document Image

图1-7 串行化读取数据在View窗口中显示结果