前言

故事的开始,是一个菜鸡要开始做毕设。然后…为了实现用C语言度MATLAB的.mat文件,大概划了半个月的水…现在交完毕设终稿,就来整理一下啦!(虽然我猜后面可能也不一定要用C读.mat了23333)
划水心路历程如下:stage1.先花了2-3天时间到处搜罗优秀网友们实现用C读取mat文件的实例,然后发现了matio;stage2.花了一个星期去调matio并且没有成功(;stage3.利用stage2的不完全版本算是实现了使用C读取.mat的目的。

平台:MATLAB(生成.mat文件),Visual Studio 2022
语言:MATLAB,C语言


一、使用matio读取.mat文件

matio是一个读取.mat文件的开源代码。
官网里的东西还挺多的,除了各个版本的代码外,也有关于matio使用的user_guide(我后面基于调试matio的半成品实现功能,也有一部分是参考了这一份说明。)
具体调试过程此处先挖坑,反正也是基于大佬博客的帮助,最后也是没有调处来orz。要是后面有心情的话再填坑= =(毕竟我不太记得了)
以及确实是有很多人通过matio实现了这个功能(羡慕.jpg),但很多人里面都没有本菜鸡就是了hhh。毕竟自从大一也不怎么认真地学完C语言后,基本就没认真学过软件的编程了。

1. matio_user_guide章节设置

1. Introduction
   // 大概是对matio的介绍吧
2. Quick Start
   // 关于如何用matio实现想要的功能的介绍,大致包括:打开/创建mat文件;读写mat文件
   2.1 Opening and Creating MAT Files
   2.2 Reading Variables in a MAT File
   2.3 Writing Variables
3. Building matio
   // 大概是关于在各个平台如何使用matio的介绍
   3.1 Quick Build Guide
   3.2 Configure Options
   3.3 CMake build system
   3.4 Visual Studio
   3.5 Testsuite
4. MATLAB Variable
   // 对可以读取的数据类型进行介绍。
   // double; matrix; cell; struct

2. 下载地址

matio下载地址: matio下载官网
hdf5 下载地址: hdf5下载官网

二、利用库文件在其他工程实现读取.mat

可读取类型:double、matrix、cell、struct

1.导入库和头文件

关于Visual Studio如何导入外部库,因为有很多这方面的教程,这里先不多说。
(依然是挖个坑,万一哪天打算填坑呢?

#include "matio.h"		
#pragma comment(lib,"libmatio.lib")
#pragma comment(lib,"zlib.lib")
#pragma comment(lib,"hdf5.lib")
#pragma comment(lib,"libhdf5.lib")

其中,zlib和hdf5主要是是在使用特殊格式的.mat文件时使用。
如果要使用的只是普通的.mat文件,可以忽略这几个库(实测没有问题)。

关于特殊格式的.mat文件,官方文档的说法是:
m a t i o matio matio库可以创建 v e r s i o n _ 4 version\_4 version_4的MAT文件, v e r s i o n _ 5 version\_5 version_5的MAT文件,带有可变压缩的 v e r s i o n _ 5 version\_5 version_5的MAT文件(使用zlib构建),引入HDF5格式的MAT文件。(但是本人并没有研究过.mat这种格式的文件)

2. 打开mat文件

  • 如何创建一个新的MAT 文件; Mat_CreatVer
  • 如何打开一个存在的MAT文件并进行读写访问; Mat_Open
  • 如何关闭一个MAT文件。 Mat_Close

打开.mat文件的代码如下(以打开"xxx.mat"文件为例):
(创建MAT文件的代码可见官方文档)

void LoadStarData(void) {
	// step1: 打开MAT文件
	mat_t* matfp;
	const char* file;		// MAT文件名
	file = "xxx.mat";		// 打开工程路径下的.mat文件

	matfp = Mat_Open(file, MAT_ACC_RDONLY);
	if (NULL == matfp) {
		printf("Error opening MAT file %s!\n", file);
	}

	// step2: 读取MAT文件中保存的数据(double、matrix、cell、struct)
	// ``````
	
	// step3: 关闭MAT文件
	Mat_Close(matfp);	
}

其中,读取数据的部分在step2位置进行,将在文章后面介绍。

3. 读取matrix类型

此处先说明:因为本人属实菜得一批,所以虽然知道一般情况下声明结构体之类的变量后都需要划空间,但属实不太会操作= =。同时本人的指针也学得一塌糊涂= =。希望等后面重新自学了C语言后可以更新一下代码吧QAQ

读取matrix类型的数据(以打开xxx.mat里名为test的数组为例,test为3x3数组)

void LoadStarData(void) {
	// step1: 打开MAT文件
	// ``````见2.1
	
	// step2: 读取MAT文件中保存的数据(double、matrix、cell、struct)
	matvar_t* matvar_var = NULL;
	matvar_var = Mat_VarRead(matfp, "test");		// 读取变量数值与信息
	if (!matvar_var) {
		printf("Error read MatVar: test!\n");
		return -1;
	}	

	int iDataN = matvar_var->nbytes / matvar_var->data_size;	// 获取矩阵的大小
	double* dI = (double*)malloc(iDataN * sizeof(double));		// 分配内存		// 不知道用法对不对hhh
	memset(dI, 0, iDataN * sizeof(double));
	if (matvar_var->data_type == MAT_T_DOUBLE) {				// 判断数据类型是否是double
		const double* xData_I = (const double*)(matvar_var->data);	// 将data的值给xData_I
 		for (int i = 0; i < iDataN; ++i) {
 			printf("test[%d] = %lf\n", i, xData_I[i]);
			/*
			test[0]		test[3]		test[6]	
			test[1]		test[4]		test[7]
			test[2]		test[5]		test[8]
			*/
 		}
		memcpy(dI, xData_I, iDataN * sizeof(double));
	}

	// step3: 关闭MAT文件
	Mat_VarFree(matvar_var);
	Mat_Close(matfp);	
}

结构体matvar_t将包含以下信息:(具体说明可查看官方文档4.1节)

name		| The name may be NULL, so the field should be checked prior to use.
rank		| The minimum rank is 2.
dims		| 
class_type	| Indicates the class of variable(e.g. double-precision, structure, cell, etc)
data_type	| Indicates the type of data stored in the data field of the MATLAB variable structure.
isComplex	| 
isLogical	| is non-zero of the variable should be interpreted as logical.
isGlobal	| 

4. 读取struct类型

同2.3处声明:本人是菜鸡,代码随缘看= =

读取struct类型数据(以读取xxx.mat文件中的test2结构体数组为例。test2结构体有两个元素,读取其中的data1(数组类型))

void LoadStarData(void) {
	// step1: 打开MAT文件
	mat_t* matfp;
	const char* file;		// MAT文件名
	file = "xxx.mat";
	const int column = 2;	// MAT文件对应的struct的元素数量。

	matfp = Mat_Open(file, MAT_ACC_RDONLY);
	if (NULL == matfp) {
		printf("Error opening MAT file %s!\n", file);
	}

	// step2: 读取MAT文件中保存的数据(double、matrix、cell、struct)
	matvar_t* structvar_patr = NULL, * data1 = NULL;							// 初始化保存数据的指针
	structvar_patr = Mat_VarRead(matfp, "test2");
	if (!structvar_patr) {
		printf("Error read MatVar: test2!\n");
	}
	else if (structvar_patr->data_type == MAT_T_STRUCT) {						// 判断读取到的内容是否为结构体
		const int list_length = structvar_patr->nbytes / structvar_patr->data_size / column;	// list_length*1 struct
		for (i = 0; i < list_length; i++) {
			data1 = Mat_VarGetStructFieldByName(structvar_patr, "data1", i);	// 以变量名读数据,也有其他读数据的模式。
			if (data1 ) {
				const double* xData_star = (const double*)(data1->data);
				const int iDataN = data1->nbytes / data1->data_size;			// data1数组的长度
				for (j = 0; j < iDataN; j++) {
					A[i].B[j] = xData_star[j];									// 随缘
				}
			}
		}
	}

	Mat_VarFree(data1);						// 释放空间,关闭文件
	Mat_VarFree(structvar_patr);
	Mat_Close(matfp);
}

总结

没啥好说的。如上。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐