2.2 Txt文件的读取与写入
Txt文件也是我们常用的文本文件,文本文件的一个好处是可以清楚字符串的格式,并且Txt文件的保存数据和读取数据的快捷性受到业界的支持,本节着重讲解Txt文件的读取与写入操作方法。
2.2.1 Txt文件的打开
MATLAB提供了Txt文本文件的读取功能,并且操作方式有很多,最简单的外部查看Txt文件的操作,如图2-11~图2-12所示。
图2-11 鼠标右键打开
图2-12 MATLAB显示Txt文件
如图2-11所示,单击【打开】命令,则弹出一个类似于MATLAB脚本文件的文件窗口,脚本文件的内容显示和文本文件显示一致,且不会出现乱码的现象,MATLAB软件完全兼容Txt文件。
如图2-11所示,当单击【在MATLAB外部打开】命令时,则采用文本文件查看模式,如图2-13所示。
图2-13 在MATLAB外部打开
如图2-13所示,采用文本文件浏览器打开记事本。
当然,用户也可以用鼠标双击【person.txt】文件,实现打开文本文件,即得到图2-13所示文本浏览器。
2.2.2 Txt文件数据的导入
如图2-14所示data.txt的文件,采用MATLAB读取该文本数据。
图2-14 data.txt数据
如图2-11所示,选择MATLAB自带的【导入数据…】命令,弹出导入数据界面,如图2-15所示。
图2-15 导入数据GUI界面
如图2-15所示,左侧显示为文本文件内数据,数据的维数一目了然,范围为A1:A8,为列矢量,用户只需要单击图2-15箭头指向的按钮即可载入该数据,导入的数据在MATLAB工作区可以查看,如图2-16~图2-17所示。
图2-16 数据导入完成
图2-17 工作区导入读数据
如图2-17所示,导入的数据自动以VarName1命名,以此类推为VarName2、VarName3……等。
如图2-18所示,当文本文件存储为两列数据时,采用外部导入的方法即可,如图2-19所示。
图2-18 两列数据
图2-19 外部导入
如图2-19所示的数据导入,MATLAB导入数据功能,能够自动识别所输入数据。
特别的,当文本文件含有字符变量时,导入功能仍然可以轻松地完成,含字符的文本文件如图2-20所示,选择【导入数据…】命令,得到如图2-21所示结果。
图2-20 带字符的数据
图2-21 导入数据
如图2-21所示,选择【导入数据…】功能,MATLAB能够自动识别数据,即排除字符干扰,使得用户能够轻松地对有用数据进行高效处理。
然而MATLAB只会识别含字符文档的前几行字符,一旦出现数字即认为后面的所有的行的矢量均为数值类型,如图2-22和图2-23所示。
图2-22 前后带字符的数据
图2-23 数据导入识别结果
选择MATLAB【导入数据…】功能可实现数据的导入,另外MATLAB也提供了相应的可供用户加载数据的函数,例如如图2-23所示的数据导入过程,MATLAB能够自动加载数据,同时也自动生成代码,如图2-24所示。
图2-24 生成脚本和生成函数
(1)如图2-24所示,单击【生成脚本】命令,得到相应的脚本文件,如图2-25所示。
图2-25 脚本文件
保存该文件为Untitled2.m,其代码如下:
%% 导入文本文件中的数据 % 用于从以下文本文件导入数据的脚本 % % F:\MATLAB Edit 2013a\MATLAB Edit 2012B\ysw\book\GUI设计手册\第2章 \data.txt % % 要将代码扩展到其他选定数据或其他文本文件,请生成函数来代替脚本 %% 初始化变量 filename = 'F:\MATLAB Edit 2013a\MATLAB Edit 2012B\ysw\book\GUI设计手册\第2章\data.txt'; delimiter = ' '; % 定界符 startRow = 2; % 起始行 %% 将数据列作为字符串读取 formatSpec = '%s%s%[^\n\r]'; % 将数据列作为字符串读取 %% 打开文本文件 fileID = fopen(filename,'r'); % 打开文件 %% 根据格式字符串读取数据列 % 该调用基于生成此代码所用的文件的结构。如果其他文件出现错误,请尝试通过导入工具重新生成代码 dataArray = textscan(fileID, formatSpec, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'HeaderLines' ,startRow-1, 'ReturnOnError', false); % 获取数据矩阵 %% 关闭文本文件 fclose(fileID); %% 将包含数值字符串的列内容转换为数值 % 将非数值字符串替换为 NaN raw = repmat({''},length(dataArray{1}),length(dataArray)-1); for col=1:length(dataArray)-1 raw(1:length(dataArray{col}),col) = dataArray{col}; % 结构体转化为数值矩阵 end numericData = NaN(size(dataArray{1},1),size(dataArray,2)); for col=[1,2] % 将输入元胞数组中的字符串转换为数值。已将非数值字符串替换为 NaN rawData = dataArray{col}; for row=1:size(rawData, 1); % 创建正则表达式以检测并删除非数值前缀和后缀 regexstr = '(?<prefix>.*?)(?<numbers>([-]*(\d+[\,]*)+[\.]{0,1}\d* [eEdD]{0,1}[-+]*\d*[i]{0,1})|([-]*(\d+[\,]*)*[\.]{1,1}\d+[eEdD]{0,1}[-+]*\d*[i]{0,1}))(?<suffix>.*)'; try result = regexp(rawData{row}, regexstr, 'names'); numbers = result.numbers; % 在非千位位置中检测到逗号 invalidThousandsSeparator = false; if any(numbers==','); thousandsRegExp = '^\d+?(\,\d{3})*\.{0,1}\d*$'; if isempty(regexp(thousandsRegExp, ',', 'once')); numbers = NaN; invalidThousandsSeparator = true; end end % 将数值字符串转换为数值 if ~invalidThousandsSeparator; numbers = textscan(strrep(numbers, ',', ''), '%f'); numericData(row, col) = numbers{1}; raw{row, col} = numbers{1}; end catch me end end end %% 将非数值元胞替换为 NaN R = cellfun(@(x) ~isnumeric(x) && ~islogical(x),raw); % 查找非数值元胞 raw(R) = {NaN}; % 替换非数值元胞 %% 将导入的数组分配给列变量名称 ysw = cell2mat(raw(:, 1)); % cell转化为mat格式文件 person = cell2mat(raw(:, 2)); % cell转化为mat格式文件 %% 清除临时变量 clearvars filename delimiter startRow formatSpec fileID dataArray ans raw col numericData rawData row regexstr result numbers invalidThousandsSeparator thousandsRegExp me R;
用户可直接运行Untitled2.m,则MATLAB工作区将自动得到相应的加载数据。
(2)如图2-24所示,单击【生成函数】命令,得到相应的函数文件,如图2-26所示。
图2-26 自动生成加载数据函数文件
如图2-26所示,MATLAB自动生成一个importfile1.m函数文件,用户可以输入数据,即可实现数据的加载,具体的importfile1.m函数文件如下:
function [ysw1,person1] = importfile1(filename, startRow, endRow) %IMPORTFILE1 将文本文件中的数值数据作为列矢量导入 % [YSW1,PERSON1] = IMPORTFILE1(FILENAME) 读取文本文件 FILENAME 中默认选定范围的数据 % % [YSW1,PERSON1] = IMPORTFILE1(FILENAME, STARTROW, ENDROW) 读取文本文件 % FILENAME的STARTROW起始行到ENDROW终止行中的数据 % % Example: % [ysw1,person1] = importfile1('data.txt',2, 10); % 导入数据调用格式 %% 初始化变量 delimiter = ' '; % 定界符,终止符 if nargin<=2 startRow = 2; % 起始行 endRow = inf; % 结束行 end %% 将数据列作为字符串读取 % 有关详细信息,请参阅 TEXTSCAN 文档 formatSpec = '%s%s%[^\n\r]'; %% 打开文本文件 fileID = fopen(filename,'r'); %% 根据格式字符串读取数据列 % 该调用基于生成此代码所用的文件的结构。如果其他文件出现错误,请尝试通过导入工具重新生成代码 dataArray = textscan(fileID, formatSpec, endRow(1)-startRow(1)+1, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'HeaderLines', startRow(1)-1, 'ReturnOnError', false); % 获取数据矩阵 for block=2:length(startRow) frewind(fileID); dataArrayBlock = textscan(fileID, formatSpec, endRow(block)-startRow (block)+1, 'Delimiter', delimiter, 'MultipleDelimsAsOne', true, 'HeaderLines', startRow(block)-1, 'ReturnOnError', false); for col=1:length(dataArray) dataArray{col} = [dataArray{col};dataArrayBlock{col}]; % 赋值 end end %% 关闭文本文件 fclose(fileID); %% 将包含数值字符串的列内容转换为数值 % 将非数值字符串替换为 NaN raw = repmat({''},length(dataArray{1}),length(dataArray)-1); for col=1:length(dataArray)-1 raw(1:length(dataArray{col}),col) = dataArray{col}; end numericData = NaN(size(dataArray{1},1),size(dataArray,2)); for col=[1,2] % 将输入元胞数组中的字符串转换为数值。已将非数值字符串替换为NaN rawData = dataArray{col}; for row=1:size(rawData, 1); % 创建正则表达式以检测并删除非数值前缀和后缀 regexstr = '(?<prefix>.*?)(?<numbers>([-]*(\d+[\,]*)+[\.]{0,1}\d*[eEdD]{0,1}[-+]*\d*[i]{0,1})|([-]*(\d+[\,]*)*[\.]{1,1}\d+[eEdD]{0,1}[-+]*\d*[i]{0,1}))(?<suffix>.*)'; try result = regexp(rawData{row}, regexstr, 'names'); numbers = result.numbers; % 在非千位位置中检测到逗号 invalidThousandsSeparator = false; if any(numbers==','); thousandsRegExp = '^\d+?(\,\d{3})*\.{0,1}\d*$'; if isempty(regexp(thousandsRegExp, ',', 'once')); numbers = NaN; invalidThousandsSeparator = true; end end % 将数值字符串转换为数值 if ~invalidThousandsSeparator; numbers = textscan(strrep(numbers, ',', ''), '%f'); numericData(row, col) = numbers{1}; raw{row, col} = numbers{1}; end catch me end end end %% 将非数值元胞替换为NaN R = cellfun(@(x) ~isnumeric(x) && ~islogical(x),raw); % 查找非数值元胞 raw(R) = {NaN}; % 替换非数值元胞 %% 将导入的数组分配给列变量名称 ysw1 = cell2mat(raw(:, 1)); person1 = cell2mat(raw(:, 2));
在MATLAB命令行窗口输入如下代码:
[ysw1,person1] = importfile1('data.txt',2, 10) % 调用函数
运行程序输出结果如下:
ysw1 = 201517 5337 182 8037 8241 117 406 3087 NaN person1 = 201517 201517 201517 201517 201517 201517 201517 201517 NaN
因此,用户借助该函数文件,也可以实现其他文本文件的加载。而【生成脚本】功能只限于加载某一个指定的文本文件,【生成函数】功能可实现同类型文件的数据导入。MATLAB这个自动生成代码的功能给用户提供了极大的便利。
MATLAB也提供了较简便的文本数据加载函数,具体如下:
>> ysw = load('data1.txt') % 加载数据 ysw = 201517 201517 5337 201517 182 201517
如果直接使用load('data1.txt'),MATLAB自动以ans.mat保存数据到工作区下,可供MATLAB GUI设计使用,也可供MATLAB主函数文件参数传递使用。
load('data1.txt')函数使用有其局限性,如果文本文件含有字母等变量,直接采用load('data1.txt')是不能加载的,load('data1.txt')只对单纯的数据加载有效,例如data.txt的内容如下:
ysw person 201517 201517 5337 201517 182 201517 8037 201517 8241 201517 117 201517 406 201517 3087 201517 ysw person
采用load('data.txt')进行调用,系统将提示如下信息:
>> ysw = load('data.txt') 错误使用 load ASCII 文件 data.txt 的行号 1 中的文本未知 "ysw"。
因此,用户应该根据具体的问题具体对待,当含有字符类型时,可采用MATLAB importfile函数进行数据分析。
(3)MATLAB提供了向文本文件写入和读入的功能,方便用户存储调用数据,利用MATLAB向ysw.txt文件中添加数据,程序如下:
% Designed by Yu Shengwei From SWJTU University % 2015年1月3日 clc,clear,close all % 清理命令区、清理工作区、关闭显示图形 warning off % 消除警告 feature jit off % 加速代码运行 format short % 数据类型 tic % 运算计时 A = [1,1,7,4,0,6,3,0,8,7,0; 1,8,2,8,0,3,7,8,2,4,1; 1,3,6,7,9,6,1,0,0,4,1; 1,8,3,8,2,4,5,8,0,7,4]; % 存储数据A save ysw.txt A -ascii;
运行程序输出结果如下:
1.0000000e+00 1.0000000e+00 7.0000000e+00 4.0000000e+00 0.0000000e+00 6.0000000e+00 3.0000000e+00 0.0000000e+00 8.0000000e+00 7.0000000e+00 0.0000000e+00 1.0000000e+00 8.0000000e+00 2.0000000e+00 8.0000000e+00 0.0000000e+00 3.0000000e+00 7.0000000e+00 8.0000000e+00 2.0000000e+00 4.0000000e+00 1.0000000e+00 1.0000000e+00 3.0000000e+00 6.0000000e+00 7.0000000e+00 9.0000000e+00 6.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00 4.0000000e+00 1.0000000e+00 1.0000000e+00 8.0000000e+00 3.0000000e+00 8.0000000e+00 2.0000000e+00 4.0000000e+00 5.0000000e+00 8.0000000e+00 0.0000000e+00 7.0000000e+00 4.0000000e+00
由结果可知,MATLAB向文本文件写入数据,默认为longE类型,生成的数据和写入的数据一致,用户可以将txt数据加载到MATLAB进行分析,因此在MATLAB中文本文件数据写入较简便。
当MATLAB再次向同一文本文件写入数据时,MATLAB将自动清空该文本文件中的所有数据,然后再写入该数据,例如再次写入数据如下:
A = [1,1,7,4,0,6,3,0,8,7; 1,8,2,8,0,3,7,8,2,4; 1,3,6,7,9,6,1,0,0,4; 1,8,3,8,2,4,5,8,0,7];
运行程序输出结果如下。
1.0000000e+00 1.0000000e+00 7.0000000e+00 4.0000000e+00 0.0000000e+00 6.0000000e+00 3.0000000e+00 0.0000000e+00 8.0000000e+00 7.0000000e+00 1.0000000e+00 8.0000000e+00 2.0000000e+00 8.0000000e+00 0.0000000e+00 3.0000000e+00 7.0000000e+00 8.0000000e+00 2.0000000e+00 4.0000000e+00 1.0000000e+00 3.0000000e+00 6.0000000e+00 7.0000000e+00 9.0000000e+00 6.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00 4.0000000e+00 1.0000000e+00 8.0000000e+00 3.0000000e+00 8.0000000e+00 2.0000000e+00 4.0000000e+00 5.0000000e+00 8.0000000e+00 0.0000000e+00 7.0000000e+00
为了直观地说明该问题,写入1,具体程序如下:
A=[1]; %存储数据A save ysw.txt A -ascii;
运行程序输出结果如下:
1.0000000e+00
MATLAB还提供了一个文本文件数据追加功能,即向已经生成的文本文件追加数据,而不是对原先数据进行覆盖处理,那么怎么进行数据追加呢?具体操作如下:
clc,clear,close all % 清理命令区、清理工作区、关闭显示图形 warning off % 消除警告 format short % 数据类型 tic % 运算计时 A = [1,1,7,4,0,6,3,0,8,7; 1,8,2,8,0,3,7,8,2,4; 1,3,6,7,9,6,1,0,0,4; 1,8,3,8,2,4,5,8,0,7]; % 矩阵A B=[1]; % 存储数据A save ysw.txt A -ascii; % 追加存储数据N save ysw.txt B -append -ascii; toc % 计时结束
追加数据后,ysw.txt文本文件数据如下:
1.0000000e+00 1.0000000e+00 7.0000000e+00 4.0000000e+00 0.0000000e+00 6.0000000e+00 3.0000000e+00 0.0000000e+00 8.0000000e+00 7.0000000e+00 1.0000000e+00 8.0000000e+00 2.0000000e+00 8.0000000e+00 0.0000000e+00 3.0000000e+00 7.0000000e+00 8.0000000e+00 2.0000000e+00 4.0000000e+00 1.0000000e+00 3.0000000e+00 6.0000000e+00 7.0000000e+00 9.0000000e+00 6.0000000e+00 1.0000000e+00 0.0000000e+00 0.0000000e+00 4.0000000e+00 1.0000000e+00 8.0000000e+00 3.0000000e+00 8.0000000e+00 2.0000000e+00 4.0000000e+00 5.0000000e+00 8.0000000e+00 0.0000000e+00 7.0000000e+00 1.0000000e+00
由此,我们将很容易向文本文件中添加数据或删减数据。