3. 文件I/O接口实战
工程数据文件没有统一格式,MATLAB 也没有一把万能钥匙。真正决定读写策略的,是三个问题:数据是文本还是二进制、是否自描述、单次能否全部装入内存。文本文件(CSV/TXT)可读性最好但解析慢、体积大;二进制文件(.bin/.dat)紧凑高效但必须知道数据类型和排列方式;Excel 适合小规模表格与人工核对;HDF5 与 NetCDF 属于自描述的分层科学数据格式,支持按变量、按切片读取,是大型仿真与观测数据的首选。下面按“先判断、再选接口、后处理大文件”的顺序展开。
文本文件:readmatrix / writematrix 与底层控制
对规整的数值表格,优先用 readmatrix 和 writematrix,它们会自动跳过表头、识别分隔符。示例:一个名为 sensor_log.csv 的文件,前两行为注释与列名,数据列为时间(s)、温度(℃)、压力(kPa):
% 读取:跳过前2行,指定分隔符
opts = detectImportOptions('sensor_log.csv');
opts.DataLines = [3, Inf];
opts.Delimiter = ',';
M = readmatrix('sensor_log.csv', opts); % M 为 N×3 double
% 写出:保留6位有效数字,带列名
writematrix(M, 'clean.csv', 'Delimiter', ',', ...
'WriteMode', 'overwrite');
当文件格式不规则(混合文本与数字、变长行)时,改用底层接口:fopen 打开句柄,fgetl 逐行读取,textscan 按格式串解析,最后 fclose 关闭。关键点是格式串必须与真实字段一一对应,例如 '%f%f%f' 对应三个浮点数;若某行字段数不足,textscan 会返回空值,需要在循环中判断并跳过。文本写入用 fprintf,注意用 %g 控制精度、用 \n 换行,避免写出科学计数法导致下游工具误读。
二进制文件:fread / fwrite 与精度、字节序
二进制读写的核心是“精度 + 排列 + 字节序”三要素。假设一个采集卡输出 int16 小端、按列优先存储的 4 通道数据,每通道 1000 点:
fid = fopen('daq.bin', 'r', 'l'); % 'l' = little-endian
raw = fread(fid, [4, 1000], 'int16=>double');
fclose(fid);
data = raw'; % 转成 1000×4,每列一通道
这里 'int16=>double' 表示以 int16 读入并转换为 double,避免后续运算溢出。[4, 1000] 指定按列填充,因此读出的矩阵每列对应一个通道。若字节序写错,读出的数值会出现数量级异常(如 1 变成 256),这是排查二进制问题最快的信号。写入时用 fwrite(fid, data', 'int16'),并保持与读取一致的字节序和维度顺序。
Excel:readtable / writetable 与区域控制
Excel 文件适合带表头、多工作表的工程记录。用 readtable 读取时,'Sheet' 指定工作表,'Range' 指定区域,'VariableNamingRule','preserve' 保留原始列名:
T = readtable('test_report.xlsx', 'Sheet', 'Run03', ...
'Range', 'B4:F200', 'VariableNamingRule', 'preserve');
writetable(T, 'summary.xlsx', 'Sheet', 'Summary', ...
'WriteMode', 'overwritesheet');
注意 Excel 的日期列常被读成数值或文本,需用 datetime 显式转换;大表(数万行以上)用 readtable 会明显变慢,此时应改用 readcell 仅取必要区域,或直接转存为 CSV/HDF5。
HDF5 与 NetCDF:自描述分层数据
HDF5 用 h5read / h5write,NetCDF 用 ncread / ncwrite。两者都支持“只读需要的切片”,这是处理大文件的关键。例如一个 HDF5 文件 sim.h5 内含数据集 /result/temperature,维度为 500×500×200(空间×空间×时间),只取第 100 个时间层:
info = h5info('sim.h5', '/result/temperature');
slice = h5read('sim.h5', '/result/temperature', ...
[1 1 100], [500 500 1]); % 起始索引 + 读取数量
NetCDF 类似:ncread('model.nc','temp',[1 1 100],[500 500 1])。注意 MATLAB 的 HDF5/NetCDF 索引从 1 开始,而文件内部多为 0 基,接口已做转换,但 start 与 count 必须严格对应维度顺序。读取前先用 h5info 或 ncinfo 查看变量名、维度、数据类型和属性(单位、缺失值 _FillValue),再决定切片范围,可避免一次性载入数 GB 数据。
大文件与流式数据:分块、切片、追加
当文件远大于可用内存时,核心原则是“不要一次读完”。四种常用手段:其一,用 datastore 建立数据仓库,read 每次取一个块,配合 while hasdata(ds) 循环处理,适合 CSV 与图像集合;其二,对二进制文件用循环 fread 固定块大小(如每次 100 万点),处理完立即覆盖变量;其三,对 HDF5/NetCDF 用切片读取,只取当前分析需要的维度区间;其四,用 memmapfile 把大二进制映射为内存数组,按索引访问而不整体载入。
流式写入则用追加模式:fopen('out.bin','a'),在循环中 fwrite 每个计算块,最后 fclose。这样即使中途中断,已写数据仍然有效。判断是否处理成功,可对比“读入总点数 / 写出总点数”是否一致,并抽查首尾若干点的数值范围是否落在物理量程内(如温度 −40~125 ℃、压力 0~10 MPa),若出现 NaN 或越界值,应回到格式串、字节序或缺失值处理上排查。