从 C++ 文件中导入 5 级 MAT 文件格式数据

Posted

技术标签:

【中文标题】从 C++ 文件中导入 5 级 MAT 文件格式数据【英文标题】:import Level 5 MAT-File Format data from file in C++ 【发布时间】:2012-01-19 11:30:29 【问题描述】:

我正在用 C++ 编写一个函数来加载基于 MATLAB® 的 MAT 文件(第 5 级)格式 MAT-File Format 2011b doc(参见 www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf)。

我必须遗漏一些东西(可能是 C++),因为字节数字段为零。 MAT-File 标头已成功读取,数据类型元素标志也是如此,但字节数未成功。加载mat文件的代码如下:

// file handler
ifstream file;
// open file
file.open(i_file, ifstream::in | ifstream::binary);
// check for errors
if (!file) return NULL;

/********** BEGIN MAT-File Header **********/
char header_text[116], header_offset[8], header_version[2], header_endian[2];
// The first 116 bytes of the header can contain text data in human-readable form.
file.read( (char*) &header_text, 116); cout << header_text << endl;
/* Header Subsystem Data Offset Field */
// Bytes 117 through 124 of the header contain an offset to subsystem-specific
// data in the MAT-file. 
file.read( (char*) &header_offset, 8); cout << header_offset << endl;
/* Header Flag Fields */
// Version When creating a MAT-file, set this field to 0x0100.
file.read( (char*) &header_version, 2); cout << header_version << endl;
// Endian Indicator. Contains the two characters, M and I, written to the
// MAT-file in this order, as a 16-bit value. 
file.read( (char*) &header_endian, 2); cout << header_endian << endl;

/********** END MAT-File Header **********/

/********** BEGIN MAT-File Data Element **********/

/* The Tag Field */
// The 8-byte data element tag is composed of two, 32-bit fields 
// Data Type
__int32_t data_type = file.get(); cout << data_type << endl;
// Number of Bytes
__int32_t num_bytes = file.get(); cout << num_bytes << endl;

输出如下:

MATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Fri May 20 18:21:46 2011


IM
15
0

我从 MATLAB 获得信息:

谁 - 文件 PaviaU.mat

名称大小字节类属性

paviaU 610x340x103 170897600 双

我是否以某种方式错误地从标头加载数据? 为什么字节数为零?

编辑:如果我按如下方式阅读数据元素(在一条评论中建议):

char data_type[4], num_bytes[4];
file.read((char*) &data_type, 4); cout << data_type << endl;
file.read((char*) &num_bytes, 4); cout << num_bytes << endl;

我在cout(二进制代码)上得到了意外的值

但调试函数我可以检查两个变量:

data_type[0] = 15
data_type[1] = 0 '\0'
data_type[2] = 0 '\0'
data_type[3] = 0 '\0'

num_bytes[0] = -3/253
num_bytes[1] = 27
num_bytes[2] = 19
num_bytes[3] = 2

data_type 的值为 15,但 num_bytes 中的 -3/253 呢?那是哪个号码?

【问题讨论】:

代码示例中的注释说标签由两个 32 位字段组成。但是您只读取 2 个字节(通常为 16 位)。 get() 只读取一个char 改用file.read((char*) &amp;data_type, 4);file.read((char*) &amp;num_bytes, 4) @jrok 谢谢你的建议。我已经用新的输出更新了问题。 我猜 num_bytesdata_type 应该是无符号值。 -3/253 是以签名/未签名形式从文件中读取的值(char 显然已在您的平台上签名)。将num_bytesdata_type 的声明更改为uint32_t 类型,应该没问题。 【参考方案1】:

根据规范,您的结果显示的数据类型是

miCOMPRESSED:压缩数据

大小字段显示您的数据大小为 0x02131BFD 或 34,806,781 字节。与您的原始大小 170MB 相比,此压缩率似乎合理,具体取决于您的数据。

假设您可以节省 140MB,将文件保存为未压缩数据可能会更容易。另存为旧 .mat 版本禁用压缩 (mathworks)。我不知道在新的 .mat 文件中禁用它的方法。

编辑

大小和数据类型字段可以更好地理解为:

uint32_t data_type, num_bytes;
file.read(reinterpret_cast<char*>(&data_type), sizeof(uint32_t));
file.read(reinterpret_cast<char*>(&num_bytes), sizeof(uint32_t));

这可以直接完成,因为您的机器是小端的。 endian 字段的结果是否相反,您必须在将所有字节存储到 uint32 之前交换它们的顺序。

【讨论】:

感谢您的建议。我仍然缺少关于 num_bytes 值的信息。你是怎么得到 0x02131BFD 值的? 您发布的数组。 num_bytes = 2, 19, 27, 253。十六进制,0x02, 0x13, 0x1B, 0xFD。被视为 4 字节字,这是 0x02131BFD。 虽然你可以直接读入单词而不是做所有这些,即uint32_t num_bytes; file.read(&amp;num_bytes, 4); 没错。此外,mat 文件的大小为 34806917 字节。我不得不使用 file.read( reinterpret_cast(&num_bytes), 4 );而不是你的建议。如果您完成答案会很棒。无论如何,关于 num_bytes 大小的问题解决了。谢谢。

以上是关于从 C++ 文件中导入 5 级 MAT 文件格式数据的主要内容,如果未能解决你的问题,请参考以下文章

Kettle从文本中导入大量到数据库

在python中导入matlab(.mat)数据

如何从html文件中导入内容 为c++中结构体初始化使用

Sequelize 6 从文件中导入模型

PE文件格式中导入表和ITA表总结20180508

python从Microsoft Excel文件中导入数据