loadmat 读取 MATLAB -v6 文本乱码,何时指定 cp1252
MATLAB Windows 导出的特定 -v6 文件在 SciPy 1.18.1 中可能乱码或报缓冲区太小。按文件实际字符编码选择 uint16_codec,避免把 latin1 当万能修复。
MATLAB 文件中的数值数组读得出来,字符串却出现 �;另一份文件甚至在 loadmat() 内报 TypeError: buffer is too small for requested array。如果文件来自 Windows MATLAB 的 -v6 导出,应检查字符编码,不能仅凭“缓冲区太小”就认定文件被截断。
一组明确的触发条件是 Windows MATLAB R2022b 写出的 -v6 文件,SciPy 1.18.1 读取其中的 miUINT16 字符数据。部分文本按 Windows-1252 字符码存储;SciPy 未收到 uint16_codec 时使用 Python 默认编码,即 UTF-8,因而可能解错。这里的存储类型名称不表示所有文件都应强行用 UTF-16 解码。
编码由文件的生成方式决定
保留原始 .mat 文件,并记录 MATLAB 版本、生成平台、save 使用的格式和预期文本。只看乱码后的 Python 字符串,通常不足以可靠猜出原编码。
对已确认采用 Windows-1252 字符码的这类文件,显式指定:
from scipy.io import loadmat
data = loadmat("input-v6.mat", uint16_codec="cp1252")
input-v6.mat 是待读取文件路径。这一步只改变本次字符读取,不修改文件,也不需要改系统区域或 Python 的全局默认编码。它是针对已知文件编码的处理,不是对所有 Windows .mat 文件的统一设置。
如果导出方式不同,例如较新的 MATLAB 文件格式或其他平台生成的数据,先按实际格式核对。MATLAB 7.3 的 HDF5 文件也不属于这条 loadmat 字符解码路径,不能用同一个参数解决格式支持问题。
latin1 不报错,仍可能解错符号
latin1 能将每个字节映射为字符,容易使读取过程不再抛异常,但这不能证明文本正确。Windows-1252 中的欧元符号和千分号,与 latin1 的对应码位不同;误用后可能留下 U+0080、U+0089 一类控制字符。
验收样本应包含真实数据中的非 ASCII 字符,例如变音字母、度数、微符号,以及欧元和千分号。逐项与 MATLAB 中的预期字符比较,不能只检查“中文或英文大致能看”。已经出现 U+FFFD 的解码结果通常不能靠再编码恢复原信息,应从保留的原文件重读。
不要在加载后用 errors="ignore" 删除无法处理的字符,也不要全局把 � 替换为空格。文本可能参与变量命名、单位显示或数据关联,删除字符会把读取失败变成无声的数据变化。
读取通过后,还要检查数值和形状
同一次读取应比较字符串数组形状、变量名、单位文本,以及关键数值变量的 dtype 和内容。原先失败的调用可能没有完整返回字典,不能把另一轮部分产物混入这次结果。
如果指定与文件匹配的编码后仍报缓冲区异常,保留新的堆栈,再查文件完整性、字符数组结构及读取版本;不要继续轮换编码直到碰巧不报错。SciPy 1.18.1 仍采用上述默认编码逻辑,并不存在一个已核实可自动识别所有 -v6 字符集的默认设置。长期交换数据时,应由生成端和读取端明确约定格式与文本编码。


