ste*_*ger 4 file-io matlab ascii file cell
我想在一个步骤中将一个(相当大的)日志文件读入MATLAB字符串单元格.我用过通常的:
s={};
fid = fopen('test.txt');
tline = fgetl(fid);
while ischar(tline)
s=[s;tline];
tline = fgetl(fid);
end
Run Code Online (Sandbox Code Playgroud)
但这很慢.我发现了
fid = fopen('test.txt');
x=fread(fid,'*char');
Run Code Online (Sandbox Code Playgroud)
更快,但我得到一个nx1char矩阵,x.我可以尝试转换x为字符串单元格,但后来我进入char编码地狱; 行分隔符似乎是\n\r,或者是ASCII中的 10和56 (我看过第一行的末尾),但这两个字符通常不会相互跟随,甚至有时会出现独奏.
有一种简单快捷的方法可以一步将ASCII文件读入字符串单元格,还是转换x为字符串单元格?
通过fgetl阅读:
Code Calls Total Time % Time
tline = lower(fgetl(fid)); 903113 14.907 s 61.2%
Run Code Online (Sandbox Code Playgroud)
通过恐惧阅读:
>> tic;for i=1:length(files), fid = open(files(i).name);x=fread(fid,'*char*1');fclose(fid); end; toc
Elapsed time is 0.208614 seconds.
Run Code Online (Sandbox Code Playgroud)
我测试了预分配,它没有帮助:(
files=dir('.');
tic
for i=1:length(files),
if files(i).isdir || isempty(strfind(files(i).name,'.log')), continue; end
%# preassign s to some large cell array
sizS = 50000;
s=cell(sizS,1);
lineCt = 1;
fid = fopen(files(i).name);
tline = fgetl(fid);
while ischar(tline)
s{lineCt} = tline;
lineCt = lineCt + 1;
%# grow s if necessary
if lineCt > sizS
s = [s;cell(sizS,1)];
sizS = sizS + sizS;
end
tline = fgetl(fid);
end
%# remove empty entries in s
s(lineCt:end) = [];
end
toc
Run Code Online (Sandbox Code Playgroud)
经过的时间是12.741492秒.
比原来大约快10倍:
s = textscan(fid, '%s', 'Delimiter', '\n', 'whitespace', '', 'bufsize', files(i).bytes);
Run Code Online (Sandbox Code Playgroud)
我必须设置'whitespace'为''保持前导空格(我需要解析),并将'bufsize'设置为文件大小(默认值4000会引发缓冲区溢出错误).
第一个例子很慢的主要原因是s每次迭代都会增长.这意味着重新创建一个新数组,复制旧行并添加新行,这会增加不必要的开销.
为了加快速度,您可以预先分配 s
%# preassign s to some large cell array
s=cell(10000,1);
sizS = 10000;
lineCt = 1;
fid = fopen('test.txt');
tline = fgetl(fid);
while ischar(tline)
s{lineCt} = tline;
lineCt = lineCt + 1;
%# grow s if necessary
if lineCt > sizS
s = [s;cell(10000,1)];
sizS = sizS + 10000;
end
tline = fgetl(fid);
end
%# remove empty entries in s
s(lineCt:end) = [];
Run Code Online (Sandbox Code Playgroud)
这是预分配可以为您做的一个小例子
>> tic,for i=1:100000,c{i}=i;end,toc
Elapsed time is 10.513190 seconds.
>> d = cell(100000,1);
>> tic,for i=1:100000,d{i}=i;end,toc
Elapsed time is 0.046177 seconds.
>>
Run Code Online (Sandbox Code Playgroud)
编辑
作为替代方案fgetl,您可以使用TEXTSCAN
fid = fopen('test.txt');
s = textscan(fid,'%s','Delimiter','\n');
s = s{1};
Run Code Online (Sandbox Code Playgroud)
这将一行中的test.txt字符串行读入单元格数组s.
小智 5
我倾向于使用urlread,例如:
filename = 'test.txt';
urlname = ['file:///' fullfile(pwd,filename)];
try
str = urlread(urlname);
catch err
disp(err.message)
end
Run Code Online (Sandbox Code Playgroud)
然后,变量str包含一个字符串类型的大块文本(准备好运行regexp).