2014-02-05 197 views
1

我正在嘗試處理system('./foo')命令的輸出。如果我直接將輸出重定向到一個帶有system('./foo > output')的文件,並通過dlmread將文件讀入MATLAB,它可以正常工作,但我試圖避免在每次執行此操作時在硬盤上寫入一個巨大的ASCII文件(大約1e7行) 。按分隔符分割大字符串

所以我想通過將它讀入一個巨大的字符串並分割字符串來直接處理輸出。它工作正常的小檔案:

[a,b] = system('./foo') 
b=strsplit(b); 
cellfun(@str2num, bb); 
b=cellfun(@str2num, b(1:end),'UniformOutput',0); 
b=cell2mat(b); 

不幸的是,這已經消耗在的strsplit操作方式太多內存步驟,使MATLAB得到由OOM殺手殺害。 我找到了替代方案:

b=textscan(b,'%s','delimiter',' ','multipleDelimsAsOne',1); 

但也消耗了太多的記憶。

有人可以幫助我更好地瞭解如何拆分該數字串並將其讀入矩陣或通常如何避免將命令的輸出寫入硬盤上的文件?

編輯:(我在這裏寫作,因爲在評論中沒有足夠的空間...) @ MZimmerman6我現在試過了dlmread的一個版本,有和沒有預先分配和你的建議以及我的理解: 實際上,循環比dlmread慢得多。

clear all 
close all 
tic 
ttags1=dlmread('tmp.txt',' ',1,3); 

toc 

clear all 

tic 
[~,result]=system('perl -e ''while(<>){};print$.,"\n"'' tmp.txt'); 
numLines1=str2double(result); 
ttags=zeros(numLines1,1); 
ttags=dlmread('tmp.txt',' ',1,3); 

toc 

clear all 

tic 
fid = fopen('tmp.txt'); 
count = 1; 
[~,result]=system('perl -e ''while(<>){};print$.,"\n"'' tmp.txt'); 
numLines1=str2double(result); 
temp = cell(numLines1,1); 
for i = 1:numLines1 
    tline = fgetl(fid); 
    if ischar(tline) 
     vals = textscan(tline,'%f','delimiter',','); 
     temp{i} = transpose(vals{1}); 
    end 
end 
fclose(fid); 
temp = cell2mat(temp); 

toc 

結果是:

Elapsed time is 19.762470 seconds. 
Elapsed time is 21.546079 seconds. 
Elapsed time is 796.755343 seconds. 

謝謝&問候

難道我做錯了什麼?

回答

1

您不應該嘗試將整個文件讀入內存,因爲這可能會非常沉重。我建議逐行讀取文件,並分別處理每個文件,然後將結果存儲到單元格數組中。然後,您可以在解析完成後將其轉換爲常規矩陣。

我可以做的第一件事是創建一個小的Perl腳本來計算您正在閱讀的文件中的行數,以便爲數據預先分配內存。把這個文件叫做countlines.pl。信息從here

Perl的聚集 - Countlines.pl

while (<>) {}; 
print $.,"\n"; 

該文件將只兩行,但會很快計算文件中的總線條。

然後,您可以使用此文件的結果進行預先分配,然後逐行解析。我在測試中使用了一個簡單的逗號分隔文件,因此您可以調整文本掃描來處理您想要的內容。

MATLAB腳本

% get number of lines in data file 
numLines = str2double(perl('countlines.pl','text.txt')); 
fid = fopen('text.txt'); 
count = 1; 
temp = cell(numLines,1); 
for i = 1:numLines 
    tline = fgetl(fid); 
    if ischar(tline) 
     vals = textscan(tline,'%f','delimiter',','); 
     temp{i} = transpose(vals{1}); 
    end 
end 
fclose(fid); 
temp = cell2mat(temp); 

這應該運行相對較快取決於你的文件的大小,以及你想要做什麼。當然,你可以編輯循環內部的解析過程,但這應該是一個很好的起點。

請注意,如果不是完全有必要的話,請勿嘗試將大量內容讀入內存中

+0

+1。其他方法快速計數線[這裏](http://stackoverflow.com/questions/12176519/is-there-a-way-in-matlab-to-determine-the-number-of-lines-in-a-文件沒有循環)。 ('>){}; print $。,「\ n」''text.txt'){[〜,result] = system('perl -e''){ – horchler

+0

} ;''numLines = str2double(result);'?還是使用文件使其更快或者這只是不跨平臺? – horchler

+0

好的,謝謝你的回答!我確實會檢查我是否可以避免一次加載整個文件。 我只是想知道爲什麼你用單元格數組來讀取數據?如果我知道我想讀取數字,比用零分配空間(numLines,1)好嗎?再次感謝horchler! – Mechanix