立即将整个文本文件读入MATLAB变量

时间:2010-08-21 11:57:18

标签: file matlab file-io ascii cell

我想在一个步骤中将一个(相当大的)日志文件读入MATLAB字符串单元格。我使用了通常的:

s={};
fid = fopen('test.txt');
tline = fgetl(fid);
while ischar(tline)
   s=[s;tline];
   tline = fgetl(fid);
end

但这很慢。我发现了

fid = fopen('test.txt');
x=fread(fid,'*char');

速度更快,但我得到一个nx1字符矩阵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%

通过fread阅读:

>> 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.

我测试了预分配,但没有帮助:(

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

经过的时间是12.741492秒。

比原版快10倍:

s = textscan(fid, '%s', 'Delimiter', '\n', 'whitespace', '', 'bufsize', files(i).bytes);

我必须将'whitespace'设置为''以保留前导空格(我需要进行解析),并将'bufsize'设置为文件大小(默认值为4000)溢出错误)。

5 个答案:

答案 0 :(得分:6)

第一个例子很慢的主要原因是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) = [];

以下是预分配可以为您做什么的一个小例子

>> 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.
>> 

修改

作为fgetl的替代方案,您可以使用TEXTSCAN

fid = fopen('test.txt');
s = textscan(fid,'%s','Delimiter','\n');
s = s{1};

这一次将test.txt的行作为字符串读入单元格数组s

答案 1 :(得分:5)

我倾向于使用urlread,例如:

filename = 'test.txt';
urlname = ['file:///' fullfile(pwd,filename)];
try
    str = urlread(urlname);
catch err
    disp(err.message)
end

变量str然后包含一个字符串类型的大块文本(准备好运行regexp)。

答案 2 :(得分:1)

使用fgetl功能代替fread。有关详细信息,请转到here

答案 3 :(得分:1)

s = regexpfileread('test.txt'),'(\r\n|\n|\r)','拆分');

Matlab regexp文档中的贝壳示例直接就位。

答案 4 :(得分:0)

以下方法是基于乔纳斯在上文中提出的,我非常喜欢。但是,我们得到的是一个单元数组s。而不是单个字符串。

我发现还有另外一行代码,我们可以得到一个字符串变量,如下所示:

% original codes, thanks to Jonas

fid = fopen('test.txt');
s = textscan(fid,'%s','Delimiter','\n');
s = s{1};

% the additional one line to turn s to a string
s = cell2mat(reshape(s, 1, []));

我发现为jsondecode(text)准备文本很有用。 :)