2010-08-21 6 views
4

Я хотел бы прочитать (довольно большой) файл журнала в ячейке строки MATLAB за один шаг. Я использовал обычное:Прочитайте весь текстовый файл в переменную 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 в ячейку строки, но затем я попал в кодировку символов; разделитель строк, кажется, \ n \ r, или 10 и 56 в ASCII (я посмотрел на конец первой строки), но эти два персонажа часто не следуют друг за другом и даже иногда появляются соло.

Есть ли простой быстрый способ чтения файла 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» к размеру файла (default 4000 сбросил ошибку переполнения буфера).

+0

Ну, вы получаете 2 секунды :). Во всяком случае, низкоуровневые функции fileIO в Matlab имеют удивительно большие накладные расходы. Я узнал об этом, когда продемонстрировал SSD RAID и практически не улучшал скорость. – Jonas

ответ

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

EDIT

В качестве альтернативы fgetl, вы могли бы использовать TEXTSCAN

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

Это читает строки test.txt в виде строки в массив s клеток в одном дыхании.

+0

Я собирался дать тот же ответ, но есть кое-что, что я не понимаю: содержимое каждой ячейки массива ячеек не определено. Помогает ли помощь в этом случае? –

+0

@Amac: Да, это так. См. Мое редактирование. – Jonas

+0

Отлично, спасибо. Чтобы быть уверенным, я воспроизвел его со строками с разной продолжительностью, и вы все равно получили огромное увеличение производительности. –

1

Используйте функцию fgetl вместо fread. Для получения дополнительной информации перейдите на страницу here

+0

Я использую fgetl, но он медленный. –

4

Я предпочитаю использовать urlread для этого, например .:

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

переменных ул затем содержит большой блок текста типа строки (готовый для регулярных выражений для работы на).

1

s = regexp (fileread ('test.txt'), '(\r\n|\n|\r)', 'split');

Пример ракушек в документации по регулярному выражению Matlab прямо на месте.