matlab如何读写⽂件,(1)MATLAB读写⽂件
另外有些⽤户希望获取⽂件的长度(字符个数),哦这个其实很简单!
fid=fopen('data.csv');
fseek(fid,0,'eof')
filelength =
ftell(fid);
fclose(fid);
复制代码
现在问题来了,如何获取⽂本⽂件的⾏数呢??下⾯我们提供⼏种解决⽅案吧!本⽂代码中测试的data.csv数据⽂件总共有10万⾏,⼤概77M。
⽅法⼀
最容易想到的就是使⽤MATLAB的fgetl或fgets函数,对⽂本按⾏读取,然后对⾏数进⾏累加。
tic
fid=fopen('data.csv'); %
打开⽂件
row=0;
while ~feof(fid) %
是否读取到⽂件结尾
[~]=fgets(fid); % 或者fgetl
row=row+1; % ⾏数累加
end
fclose(fid); %
及时关闭⽂件是个好习惯
row
toc
复制代码
运⾏结果如下,fgets⼤概耗时⼤概10s,如果fgetl速度会慢⼀些,⼤概需要13s,可能是因为fgel需要将尾部的回车去掉⽽增加了操作吧
row =
100000
Elapsed time is 10.556020 seconds.
⽅法⼆
其实MATLAB处理复杂⽂本⽂件,灵活性最好和效率最⾼的是textscan函数。灵活性就不⽤说了,textscan提供很多定制功能,⽐如跳过的标题⾏数、设置空⽩字符等经过测试;⾄于效率,经过测试,textscan在处理某些数据下是效率fscanf的10倍以上,另外仔细看看dlmread函数,其实也是调⽤了textscan函数。
接着有⼈要问,textscan是⽤来读取数据的,怎么⽤来统计⾏数?其实我们只是占了⼀个便宜⽽已!因为textscan提供了⼀个忽略特定字符串的功能。
tic
fid=fopen('data.csv');
% '%*[^\n]'
这个设置估计有⼈看不懂,特别是后⾯的那个%
% ,表⽰读取⼀个字符
%
%*[^\n],*表⽰忽略,[^]表⽰不是[]字符,合起来的意思就是忽略所有不是\n(回车)的字符,更直接的意思就是忽略到⾏尾
data =
(textscan(fid,'%*[^\n]'));
fclose(fid);
row=length(data{1})
toc
复制代码
row =
100000
Elapsed time is 12.660186 seconds.
运⾏时间12s,好像有点长哦,没有想象中的那么厉害。另外这个⽅法有两个个致命的弱点,因为程序必须每⾏读取⼀个字符
(1)假如⽂件很⼤,⽐如10G,那么就算每⾏读取⼀个字符,这个也超出了XP内存,因此读取失败!
(2)假如存在空⾏,那么会将回车读⼊,%*[^\n]于是就⾃动忽略了下⼀⾏,因此统计的⾏数不准确!
从上⾯分析textscan并不适合⽤于统计⼤型⽂件的⾏数,但是这并不能否定textscan的效率,因为textscan是千真万确⼀⾏⼀⾏的处理和读取数据⽂件,只是我们读取第⼀个字符然后忽略了剩下的所有字符⽽已。
⽅法三
其实越是底层的函数效率是越⾼的,只是使⽤不⽅便⽽已。MATLAB还有⼀个fread函数,不过这是默认处理的是⼆进制⽂件,不过没有关系,⽂本⽂件只是⼀个编码⽽已,我们还是可以使⽤fread进⾏读取的。
tic
fid=fopen('data.csv','rt');
% t是告诉fread是这⾥⽂本⽂件
row=0;
while ~feof(fid)
% ⼀次性读取10000字符,计算其中的回车个数,其中10是回车的ASCII编码
% '*char'表⽰每次读取⼀个字符,*表⽰输出也是字符
% 放⼼fread现在已经可以⾃动识别中⽂了,万⼀还是识别不了,
% 请在fopen中指定⽂件编码格式,⽐如gbk
row=row+sum(fread(fid,10000,'*char')==char(10));
% 下⾯还有⼀个类似的⽅法,但是效率低很多,⼤概是上⾯的⼀半
% 'char'表⽰每次读取⼀个字符,但是默认输出double,
% 也就是说读取char然后转换double中间有转换能快吗?
% row=row+sum(fread(fid,10000,'char')==10);
end
fclose(fid);
row
toc
复制代码
这个效率呱呱的,简直天壤之别呀,才1.7s!看来这个结果⽐较令我满意哦!
row =
100000
Elapsed time is 1.721880 seconds.
⽅法四
上⾯的⽅法都是在循环中不停地对⽂件进⾏访问,⾃然效率是⾼不起来的。对于⼤型⽂件,还有其他什么好的解决⽅案呢,也许这个时候需要借组外部⼒量了!传说perl语⾔对⽂件操作有很多优势,同时linux提供了wc命令对⽂件进⾏⾏统计,不妨试试?
tic
% 判断计算机操作系统
if (isunix) %
Linux系统提供了wc命令可以直接使⽤
% 使⽤syetem函数可以执⾏操作系统的函数
% ⽐如window中dir,linux中ls等
[~, numstr] = system( ['wc -l ', 'data.csv']
linux怎么读取windows文件);
row=str2double(numstr);
elseif (ispc) %
Windows系统可以使⽤perl命令
if exist('countlines.pl','file')~=2
%
perl⽂件内容很简单就两⾏
% while
(<>) {};
% print
$.,"\n";
fid=fopen('countlines.pl','w');
fprintf(fid,'%s\n%s','while
(<>) {};','print $.,"\n";');
fclose(fid);
end
% 执⾏perl脚本
row=str2double( perl('countlines.pl',
'data.csv') );
end
row
toc
复制代码
楼主使⽤的是window系统,调⽤perl,果然不负众望,才0.89秒
row =
100000
Elapsed time is 0.889994 seconds.
其实上⾯的⽅法在处理真正的⼤型⽂件时,还是可能不是很理想的,本⽂中测试的⽂件才77M算不上什么⼤型⽂件,后来对⼀个⼤约80万⾏,⼤⼩622M的csv⽂件进⾏测试,使⽤perl⽅法结果如下:
row =
800001
Elapsed time is 15.859564 seconds.
⽂件越⼤,计算时间不是简单的线性增加!到了真正⼏⼗甚⾄⼏百G这样的⼤型数据,上⾯的⽅法⼏乎是不能忍受的,也许还有更好的解决⽅法吧!
有⼈问有什么好的⽅法⽣成上⾯的测试数据呀?我在MATLAB中是这样⽣成的!
data=rand(10000,100); %
随机⽣成1w⾏数据
save data.csv data -ascii %
保存为⽂本
for ii=1:5 %
⾃⼰复制5次,⽣成2^5=32万⾏
% 这⾥使⽤了dos命令,效率会好些
% 千万不要使⽤fprint,否你会残废的
!type data.csv >> data.csv
end

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。