HOWTO · Python
在 Python 中读取 Matlab mat 文件
本教程演示了如何在 Python 中读取和打开 Matlab mat 文件
本页内容
MATLAB 将工作区变量保存在 .mat 文件中,而 Python 没有内置的打开方式——你需要根据 MAT 文件的版本选择读取库。本指南介绍如何识别文件的格式,并用 scipy.io、h5py、mat4py 或 matlab.engine API 加载其中的变量,同时说明每种方法在何处会失效。
根据 MAT 文件版本选择读取库
MATLAB 历史上使用过两种文件布局。5 到 7.2 版本的 MAT 文件使用 MATLAB 自己的二进制格式,并以一段以 MATLAB 起始的 128 字节文本头开始;更早期的 MATLAB 4 文件使用相同的经典布局,但没有描述性文件头——它们直接以数据元素开始。scipy.io.loadmat 可以读取整个经典系列,无论有没有文件头。用 -v7.3 保存的文件是 HDF5 文件:它们保留一个小的 MATLAB 用户块,但数据存储为 HDF5 数据集,这正是 h5py 所打开的格式。NumPy 本身无法打开这两种布局——它只是把已经加载的数据集转换成数组。
无需安装任何依赖,只要查看文件的前几个字节就能识别它。运行下面的示例,它会向一个临时文件夹各写入一个常见类型的文件,并按文件头对它们分类:
下面示例代码中的字符串以及其输出中显示的标签按约定保留英文原文。
本节中的代码以及显示的标签或输出仍为英文。
import os
import tempfile
folder = tempfile.mkdtemp()
classic = os.path.join(folder, "classic.mat")
modern = os.path.join(folder, "v73.mat")
with open(classic, "wb") as f:
f.write(b"MATLAB 5.0 MAT-file, Platform: GLNXA64, Created on: Thu Oct 29 2026".ljust(128, b" "))
with open(modern, "wb") as f:
f.write(b"MATLAB 7.3 MAT-file, Platform: GLNXA64, HDF5 schema 1.00".ljust(512, b" "))
f.write(b"\x89HDF\r\n\x1a\n")
def mat_kind(path):
with open(path, "rb") as f:
head = f.read(128)
f.seek(512)
signature = f.read(8)
if b"HDF5" in head or signature.startswith(b"\x89HDF"):
return "MATLAB 7.3 (HDF5): read with h5py"
if head.startswith(b"MATLAB"):
return "MAT-file 7.2 or older: read with scipy.io.loadmat"
return "no v5+ header or HDF5 signature — possibly a MATLAB 4 file: try scipy.io.loadmat"
print(mat_kind(classic))
print(mat_kind(modern))
MAT-file 7.2 or older: read with scipy.io.loadmat
MATLAB 7.3 (HDF5): read with h5py
真实的 7.3 文件会在其头部文本中提到 HDF5,并在用户块之后带有 HDF5 签名,而 5–7.2 版本文件的头部只是以 MATLAB 开头。该检查只根据这两个标记分类:MATLAB 4 文件两个标记都没有,因此会落入兜底消息——但 scipy.io.loadmat 仍然可以打开它,所以应把这个结果视为直接尝试 loadmat 的提示,而不是文件无法读取的证明。一般来说,文件版本为 7.2 或更旧时优先使用 scipy.io.loadmat,对 7.3 文件使用 h5py,当你想从经典文件中得到普通 Python 列表而不是 NumPy 数组时选择 mat4py,只有当 MATLAB 本身已安装、并且你需要对复杂类型的完整保真度时才使用 matlab.engine。变量进入 Python 之后,pandas 可以将它们导出为 CSV 或 Excel;如果以后需要,scipy.io.savemat 或一个 HDF5 数据集也可以把 .mat 文件写回。
下面各节使用 sample.mat(一个经典文件)和 sample_v73.mat(一个 7.3 文件),并假定它们包含一个名为 measurements 的变量。这些代码片段是依赖特定的:它们假定已安装指定的包,因此请在你自己的环境中运行,而不是在裸解释器中运行。
使用 SciPy 读取 MATLAB 文件
先用 pip install scipy 安装该库,然后调用 scipy.io.loadmat("sample.mat")。它返回一个字典:除了你的变量之外,还带有 __header__、__version__ 和 __globals__ 这些元数据键,每个 MATLAB 变量都会以其工作区名称成为一个 NumPy 数组,因此 data["measurements"] 可以直接取出该变量。
当形状看起来不对时,有两个选项值得了解。向 loadmat 传入 squeeze_me=True 会折叠 MATLAB 的单例维度,使标量以标量形式返回;与 struct_as_record=False 组合使用时,可以像访问属性一样访问结构体字段,而不是访问嵌套的数组元素。要把结果写回,scipy.io.savemat("out.mat", {"measurements": data["measurements"]}) 会生成一个经典 MAT 文件。
版本限制是重要的约束:loadmat 仅支持 7.2 及以下的 MAT 文件格式。给它一个 7.3 文件时,它会报告该格式不受支持,因为负载是 HDF5——这种文件需要下一节的方法。如果你能控制 MATLAB 一侧,用 save data.mat -v7 保存即可生成 loadmat 可以接受的文件。
使用 h5py 读取 MATLAB 7.3 文件
-v7.3 文件是带有 MATLAB 用户块的 HDF5 文件,因此只需 pip install h5py 就能打开它。h5py.File("sample_v73.mat", "r") 以读取方式打开文件,list(f.keys()) 会显示顶层组——每个 MATLAB 变量对应一个组,外加一个存放共享元胞和结构体内容的 #refs# 组。
读取 f["measurements"][()] 会把数据集具体化为 NumPy 数组;这里 NumPy 只是在做转换,因为文件是由 h5py 打开的。实践中有两个布局细节很重要。MATLAB 按列主序写入数组,因此二维数据集通常会以转置形式返回,f["measurements"][()].T 可以恢复 MATLAB 的方向。元胞数组和结构体会以指向 #refs# 的 HDF5 对象引用的形式返回,因此需要用 f[ref] 对每个条目解引用,而不是直接读取它。
使用 mat4py 读取 MATLAB 文件
pip install mat4py 提供了一个面向经典 MAT 文件的较小 API。执行 from mat4py import loadmat 之后,调用 loadmat("sample.mat") 会返回一个普通字典,其中数值数组是嵌套的 Python 列表,结构体则变成嵌套字典——当你想把数据作为纯 Python 类型使用、又不想引入 NumPy 时,这很方便。
把 mat4py 视为经典格式的读取器:它无法打开 7.3 的 HDF5 文件,深度嵌套或异常的 MATLAB 结构也可能无法干净地映射,因此它并不能替代所有 MAT 文件的读取方式。在基于它构建之前,请先用 scipy.io 验证复杂文件的转换结果。
使用 MATLAB 引擎 API 读取 MATLAB 文件
当 MATLAB 本身已安装时,它面向 Python 的引擎 API 是保真度最高的选择。用 pip 安装 matlabengine(或运行 MATLAB 自带的安装程序)后会暴露 matlab.engine,它在幕后驱动一个真实的 MATLAB 会话。eng = matlab.engine.start_matlab() 启动该会话,eng.load("sample.mat") 将文件中的所有变量加载到引擎工作区(无论文件版本如何),eng.quit() 在用完后关闭会话。返回值是 matlab.double 等 MATLAB 类型,NumPy 可以用 np.asarray 进行转换。
它的取舍在于实际条件而非文件格式:引擎需要一份有许可证的 MATLAB 安装和与之匹配的引擎版本,会话启动需要几秒钟,并且无法在纯 Python 环境中运行。这也是本节以内联方式展示调用、而不是作为独立示例的原因——只要机器上还没有安装 MATLAB,其他库才是合适的默认选择。