4 Stimmen

Lesen Sie eine ganze Textdatei auf einmal in eine MATLAB-Variable.

Ich würde gerne eine (ziemlich große) Protokolldatei in eine MATLAB-String-Zelle in einem Schritt einlesen. Ich habe das Übliche verwendet:

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

aber das ist einfach langsam. Ich habe herausgefunden, dass

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

viel schneller ist, aber ich erhalte eine nx1 Zeichenmatrix, x. Ich könnte versuchen, x in eine Zeichen-Zelle umzuwandeln, aber dann gerate ich in die Zeichenkodierungshölle; der Zeilentrenner scheint \n\r oder 10 und 56 in ASCII zu sein (ich habe das Ende der ersten Zeile angesehen), aber diese beiden Zeichen folgen sich oft nicht und tauchen manchmal sogar einzeln auf.

Gibt es einen einfachen schnellen Weg, um eine ASCII-Datei in einer Zeichen-Zelle in einem Schritt zu lesen oder x in eine Zeichen-Zelle zu konvertieren?

Lesen über fgetl:

Code                           Aufrufe        Gesamtzeit      % Zeit
tline = lower(fgetl(fid));     903113       14.907 s        61.2%

Lesen über fread:

>> tic;for i=1:length(files), fid = open(files(i).name);x=fread(fid,'*char*1');fclose(fid); end; toc

Vergangene Zeit beträgt 0.208614 Sekunden.

Ich habe die Vorzuweisung getestet, und sie hilft nicht :(

files=dir('.');
tic
for i=1:length(files),   
    if files(i).isdir || isempty(strfind(files(i).name,'.log')), continue; end
    %# weise s zu einer großen Zellenmatrix
    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;
       %# wachse s wenn notwendig
       if lineCt > sizS
           s = [s;cell(sizS,1)];
           sizS = sizS + sizS;
       end
       tline = fgetl(fid);
    end
    %# entferne leere Einträge in s
    s(lineCt:end) = [];
end
toc

Vergangene Zeit beträgt 12.741492 Sekunden.

Etwa 10 Mal schneller als das Original:

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

Ich musste 'whitespace' auf '' setzen, um die führenden Leerzeichen (die ich zum Parsen benötige) zu behalten, und 'bufsize' auf die Größe der Datei (der Standardwert 4000 führte zu einem Pufferüberlauffehler).

0 Stimmen

Nun ja, du gewinnst 2 Sekunden :). Wie auch immer, die Low-Level-Datei-Ein/Ausgabe-Funktionen in Matlab kommen mit einem erstaunlich großen Overhead. Ich habe das herausgefunden, als wir einen SSD-RAID demonstrierten und kaum eine Geschwindigkeitsverbesserung feststellten.

7voto

Jonas Punkte 74252

Der Hauptgrund, warum Ihr erstes Beispiel langsam ist, besteht darin, dass s in jeder Iteration wächst. Dies bedeutet, dass ein neues Array erstellt, die alten Zeilen kopiert und die neue hinzugefügt wird, was unnötige Overheads verursacht.

Um die Dinge zu beschleunigen, können Sie s vorher zuweisen

%# s auf ein großes Zellenarray vorzuweisen
s = cell(10000,1);
sizS = 10000;
lineCt = 1;
fid = fopen('test.txt');
tline = fgetl(fid);
while ischar(tline)
   s{lineCt} = tline;
   lineCt = lineCt + 1;
   %# wachsen s falls erforderlich
   if lineCt > sizS
       s = [s;cell(10000,1)];
       sizS = sizS + 10000;
   end
   tline = fgetl(fid);
end
%# Entfernen Sie leere Einträge in s
s(lineCt:end) = [];

Hier ist ein kleines Beispiel, was Vorzuweisung für Sie tun kann

>> tic,for i=1:100000,c{i}=i;end,toc
Die vergangene Zeit beträgt 10.513190 Sekunden.

>> d = cell(100000,1);
>> tic,for i=1:100000,d{i}=i;end,toc
Die vergangene Zeit beträgt 0.046177 Sekunden.
>> 

ÄNDERUNG

Als Alternative zu fgetl können Sie TEXTSCAN verwenden

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

Dies liest die Zeilen von test.txt als String in das Zell-Array s auf einmal.

0 Stimmen

Ich war kurz davor, die gleiche Antwort zu geben, aber es gibt etwas, das ich nicht verstehe: Der Inhalt jeder Zelle des Zellarrays ist nicht definiert. Hilft eine Vorzuweisung in diesem Fall?

0 Stimmen

Toll, danke. Nur um sicher zu gehen, habe ich es mit Zeichenfolgen unterschiedlicher Längen repliziert und Sie haben immer noch eine enorme Leistungssteigerung erlebt.

0 Stimmen

Vielen Dank für Ihre schnelle Antwort! Ich habe das Beispiel codiert, um das allgemeine Problem zu zeigen,aber nicht daran gedacht, dass das Nicht-Voraballokieren im Beispiel wahrscheinlich die Dinge verlangsamen würde. In meinem Fall analysiere ich die Zeilen sofort, d.h. es gibt keine Zeichenkette s. Das Profiling zeigt, dass etwa 60% der Zeit in der Zeile "tline = fgetl(fid);" verbracht werden (wobei der übrige Code im Moment nicht optimiert ist).

5voto

Paul Hughes Punkte 51

Ich neige dazu, urlread dafür zu verwenden, z. B .:

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

Die Variable str enthält dann einen großen Textblock vom Typ string (bereit für regexp zum Bearbeiten).

1voto

Hari Menon Punkte 31641

Verwenden Sie die fgetl-Funktion anstelle von fread. Für weitere Informationen gehen Sie hier

1voto

Ben Punkte 1232

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

Das Seashells-Beispiel in der Matlab-Regexp-Dokumentation ist direkt auf den Punkt.

0voto

ddystill Punkte 1

Die folgende Methode basiert auf dem, was Jonas oben vorgeschlagen hat, was mir sehr gut gefällt. Allerdings erhalten wir ein Zellarray s. anstatt einem einzigen String.

Ich habe herausgefunden, dass wir mit einer weiteren Codezeile eine einzelne Zeichenfolgenvariable erhalten können, wie unten gezeigt:

% Ursprüngliche Codes, dank Jonas

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

% Die zusätzliche Codezeile, um s in einen String umzuwandeln
s = cell2mat(reshape(s, 1, []));

Ich fand es nützlich, den Text für jsondecode(text) vorzubereiten. :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X