Skip to content

MATLAB - 数据导入

数据导入是大多数数据分析工作流程中的第一步。MATLAB 提供了一套强大而灵活的工具,用于从各种文件格式加载数据。虽然旧方法侧重于通用函数,但现代 MATLAB 鼓励使用针对特定数据类型量身定制的专业高性能函数,主要是用于表格数据的 readtable 和用于数值数组的 readmatrix。

对于大多数常见任务,您应该优先选择 MATLAB 的高级导入函数。它们经过性能优化,自动处理许多常见的格式问题,并将数据以方便的现代数据结构(如 table 表格和 matrix 矩阵)返回。

函数最佳用途
readtable表格数据(例如 CSV、TXT、XLSX)的推荐函数。它可以推断数据类型,处理缺失值,并将数据读取到 table 中,从而保留列标题和混合数据类型。
readmatrix非常适合包含纯数值、矩阵式数据的文件。在这些情况下,它比 readtable 更快,并返回一个标准的数值矩阵。
readcell当您拥有混合数据但需要保留文件的原始单元格结构,而不需要 table 的结构化组织时使用。
importdata一个多功能通用函数,可以处理多种文件类型,包括图像和文本文件。它是一个很好的备用选择,但与专用函数相比,有时会产生较不规范的输出格式。
webread从 RESTful Web 服务和网页读取内容。对于集成在线 API 数据至关重要。

示例 1:使用 readtable 导入表格数据

Section titled “示例 1:使用 readtable 导入表格数据”

让我们导入一个带有列标题的文本文件。这是最常见的数据导入任务。考虑一个名为 weeklydata.csv 的文件,其内容如下:

Day,Temperature,Humidity
Monday,22.5,55
Tuesday,24.1,52
Wednesday,23.8,58
Thursday,25.0,60
Friday,21.9,49

现代方法是使用 readtable。它会自动检测分隔符(逗号),识别标题行,并解析数值数据。

% 最佳实践:使用 fullfile 创建平台无关的路径
% 确保 'weeklydata.csv' 位于您当前的 MATLAB 路径中。
filename = 'weeklydata.csv';
% 使用 try-catch 块进行健壮的错误处理
try
% readtable 自动检测标题和分隔符
dataTable = readtable(filename);
% 显示导入的表格
disp('Successfully imported data as a table:');
disp(dataTable);
% 访问数据是直观的
fprintf('\nMean Temperature: %.2f\n', mean(dataTable.Temperature));
catch ME
% 提供用户友好的错误消息
fprintf('Error importing file: %s\n', ME.message);
end

当你运行该文件时,readtable 将返回一个 table 变量,这是 MATLAB 中处理混合类型列数据的现代标准。输出将是:

Successfully imported data as a table:
Day Temperature Humidity
___________ ___________ ________
"Monday" 22.5 55
"Tuesday" 24.1 52
"Wednesday" 23.8 58
"Thursday" 25 60
"Friday" 21.9 49
Mean Temperature: 23.46

importdata 仍然非常适用于非表格数据,如图像。对于图像特定任务,图像处理工具箱(Image Processing Toolbox™)中的函数,如 imread 甚至更好,但 importdata 对于快速加载非常有用。

% 确保图像文件(例如 'peppers.png',一个标准的 MATLAB 演示图像)可用。
filename = 'peppers.png';
try
imageData = importdata(filename);
% `image` 函数适用于快速显示。
% 如需更多控制,请使用 `imshow`。
figure; % 创建一个新的图形窗口
imshow(imageData);
title(['Image: ', filename], 'Interpreter', 'none');
catch ME
fprintf('Could not load or display image. Error: %s\n', ME.message);
end

低级文件 I/O 函数,如 fopen、fscanf 和 fclose,让您完全控制数据读取过程。仅当高级函数失效时才应使用它们,例如处理非标准文件格式、具有复杂结构的二进制文件,或者需要通过逐行读取文件来最小化内存使用时。

最佳实践:始终使用带有 finally 子句的 try-catch 块,以确保即使在读取过程中发生错误,fclose 也能被调用。这可以防止文件句柄保持打开状态。

主要的低级函数有:

函数描述
fopen打开文件,或获取关于已打开文件的信息。返回一个文件标识符。
fclose关闭一个或所有打开的文件。对于防止资源泄露至关重要。
fgetl从文件中读取单行文本,丢弃换行符。
textscan将数据从文本文件或字符串读取到单元格数组中。比 fscanf 更强大、更灵活。
fread从二进制文件读取数据到矩阵中。
fwrite将数据写入二进制文件。
fprintf将格式化数据写入文本文件。

示例 3:使用 textscan 进行低级 I/O

Section titled “示例 3:使用 textscan 进行低级 I/O”

让我们回顾一下原始教程中的降雨数据 (myfile.txt)。使用 fscanf 手动解析此数据既复杂又容易出错。一种更健壮的现代方法是使用 fgetl 跳过标题,并使用 textscan 读取结构化数据。

/* myfile.txt 内容 */
Rainfall Data
Months: June, July, August
M = 3
12:00:00
June-2012
17.21 28.52 39.78 16.55 23.67
19.15 0.35 17.57 NaN 12.01
...

以下是解析此文件的一种更现代、更安全的方法。

filename = 'myfile.txt';
fid = -1; % 初始化文件 ID 为无效值
try
fid = fopen(filename, 'r');
if fid == -1
error('CannotOpenFile', 'Could not open the file: %s', filename);
end
% 跳过前 3 行标题
for i = 1:3, fgetl(fid); end
% 读取月份数
headerLine = fgetl(fid);
numMonths = sscanf(headerLine, 'M = %d');
% 预分配结构体数组以提高效率
myData(numMonths) = struct('time', [], 'month', [], 'raindata', []);
% 定义数值数据块的格式(5 列浮点数)
formatSpec = '%f %f %f %f %f';
for n = 1:numMonths
fgetl(fid); % 跳过空行
myData(n).time = fgetl(fid);
myData(n).month = fgetl(fid);
% 使用 textscan 读取接下来的 7 行数值数据
dataBlock = textscan(fid, formatSpec, 7, 'CollectOutput', true);
myData(n).raindata = dataBlock{1};
end
disp('Data successfully parsed using low-level I/O.');
disp(myData);
catch ME
fprintf(2, 'An error occurred: %s\n', ME.message);
finally
% 无论是否发生错误,此块都将执行
if fid ~= -1
fclose(fid);
disp('File closed.');
end
end
  • 错误:文件未找到。 检查文件是否在当前 MATLAB 文件夹或 MATLAB 路径中。使用 pwd 查看当前文件夹,并使用 exist(filename, 'file') 检查文件是否对 MATLAB 可见。
  • 错误:数据类型或列不正确。 如果 readtable 错误地解释了您的数据,请使用其选项来指定变量名、类型和范围。使用 'Delimiter' 和 'HeaderLines' 名称-值对。
  • 性能:大文件导入缓慢。 对于非常大的文本文件,readmatrix 通常比 readtable 更快。对于内存无法完全加载的文件,请使用 datastore 以分块方式处理数据。
  • 低级 I/O:未关闭的文件。 忘记调用 fclose(fid) 会锁定文件并消耗系统资源。务必使用 try-catch-finally 结构来确保文件被关闭。