Чтение и обработка большого текстового файла в Matlab - PullRequest
4 голосов
/ 10 мая 2011

Я пытаюсь прочитать большой текстовый файл (несколько миллионов строк) в Matlab. Первоначально я использовал importdata (file_name), который выглядел как краткое решение. Однако мне нужно использовать Matlab 7 (да, я знаю его старый), и кажется, что importdata не поддерживается. Поэтому я попробовал следующее:

while ~feof(fid)    
    fline = fgetl(fid);
    fdata{1,lno} =  fline ;
    lno = lno + 1;
end

Но это действительно медленно. Я предполагаю, потому что это изменение размера массива на каждой итерации. Есть ли лучший способ сделать это. Принимая во внимание, что первые 20 строк входных данных являются данными строкового типа, а остальные данные представляют собой от 3 до 6 столбцов шестнадцатеричных значений.

Ответы [ 3 ]

5 голосов
/ 10 мая 2011

вам придется сделать некоторые изменения, но другой вариант для вас будет, вы можете использовать fread. Но, как уже упоминалось, это, по сути, блокирует вас в прямоугольном импорте. Таким образом, другой вариант будет использовать текстовое сканирование. Как я упоминаю в другом примечании, я не уверен на 100%, когда это было реализовано, все, что я знаю, это то, что у вас нет «importdata ()»

fid = fopen('textfile.txt')
Out  = textscan(fid,'%s','delimiter',sprintf('\n'));
fclose(fid)

с использованием текстового сканирования вы сможете получить массив ячеек символов для каждой строки, которыми затем сможете манипулировать по своему усмотрению. И, как я говорю в моих комментариях, это уже не имеет значения, одинаковой ли длины строки или нет. ТЕПЕРЬ вы можете быстрее проанализировать массив ячеек. Но, как упоминает gnovice, и у него тоже есть очень элегантное решение, вам, возможно, придется задуматься о требованиях к памяти.

Единственное, что вы никогда не захотите использовать в Matlab, если можете избежать этого, - это циклические структуры. Они быстры в C / C ++ и т. Д., Но в matlab они - самый медленный способ добраться туда, куда вы идете.

РЕДАКТИРОВАТЬ: Просто посмотрел, и похоже, что текстовое сканирование БЫЛО реализовано буквально в версии 7 (R14), так что если это то, что у вас есть, вы должны использовать это.

2 голосов
/ 10 мая 2011

Одним из решений является чтение всего содержимого файла в виде строки символов с помощью FSCANF , разбиение строки на отдельные ячейки в точках, где встречаются символы новой строки, с использованием MAT2CELL ,удалите лишние пробелы на концах с помощью STRTRIM , затем обработайте строковые данные в каждой ячейке по мере необходимости.Например, используя этот образец текстового файла 'junk.txt':

hi
hello
1 2 3
FF 00 FF
12 A6 22 20 20 20
FF FF FF

Следующий код поместит каждую строку в ячейку массива ячеек cellData:

>> fid = fopen('junk.txt','r');
>> strData = fscanf(fid,'%c');
>> fclose(fid);
>> nCharPerLine = diff([0 find(strData == char(10)) numel(strData)]);
>> cellData = strtrim(mat2cell(strData,1,nCharPerLine))

cellData = 

    'hi'    'hello'    '1 2 3'    'FF 00 FF'    '12 A6 22 20 20 20'    'FF FF FF'

Теперь, еслиВы хотите преобразовать все шестнадцатеричные данные (строки с 3 по 6 в моем примере файла данных) из строк в векторы чисел, вы можете использовать CELLFUN и SSCANF примерно так:

>> cellData(3:end) = cellfun(@(s) {sscanf(s,'%x',[1 inf])},cellData(3:end));
>> cellData{3:end}    %# Display contents

ans =

     1     2     3

ans =

   255     0   255

ans =

    18   166    34    32    32    32

ans =

   255   255   255

ПРИМЕЧАНИЕ: Поскольку вы имеете дело с такими большими массивами, вам нужно помнить о том, что объем памяти используется вашими переменными.Вышеупомянутое решение векторизовано, но может занять много памяти.Возможно, вам придется перезаписать или очистить большие переменные, такие как strData, при создании cellData.Кроме того, вы можете зациклить элементы в nCharPerLine и индивидуально обработать каждый сегмент более крупной строки strData в нужные вам векторы, которые вы можете предварительно выделить теперь, когда вы знаете, сколько строк данных выиметь (то есть nDataLines = numel(nCharPerLine)-nHeaderLines;).

2 голосов
/ 10 мая 2011

Я вижу два варианта:

  1. Вместо того, чтобы увеличиваться на 1 каждый раз , вы можете, например, удвоить размер вашего массива только при необходимости,Это значительно уменьшает количество необходимых перераспределений.
  2. Выполните двухпроходный подход.Первый проход просто подсчитывает количество строк, не сохраняя их.Второй проход фактически заполняет массив (который был предварительно выделен на правильный размер).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...