while文を使ったファイル終端までのデータ読み込み

一連のフォーマットがファイルの中で何回続くかわからない時に,

while ~feof(fid)

を使ってファイルの最後まで読み取る(fidはfopenで開いたファイルID).

ファイル形式例

例として,ny行nx列の値が時系列で並ぶ,とある量 f(x,y,t) を仮定し,

2017/01/01 00:00:00
f( 1, 1,1)  f( 2, 1,1) f( 3, 1,1) ... f(nx, 1,1)
f( 1, 2,1)  f( 2, 2,1) f( 3, 2,1) ... f(nx, 2,1)
f( 1, 3,1)  f( 2, 3,1) f( 3, 3,1) ... f(nx, 3,1)
    ...         ...        ...    ...     ...
f( 1,ny,1)  f( 2,ny,1) f( 3,ny,1) ... f(nx,ny,1)
2017/01/01 00:10:00
f( 1, 1,2)  f( 2, 1,2) f( 3, 1,2) ... f(nx, 1,2)
f( 1, 2,2)  f( 2, 2,2) f( 3, 2,2) ... f(nx, 2,2)
....

というように,
「時刻(1行),量(ny行),時刻(1行),量(ny行)…」
と続くファイルがあり,これを全て読み取り,変数へ格納したいとする.
textscanとfscanfで方法が異なるので別々に.

事前作業

どちらも共通の作業として,

% % preallocate
nt_upper = 1000;
header = cell(nt_upper,1);
dataorg = cell(nt_upper,1);
% % open 
fid = fopen(filename,'r');

のように,ファイルを開き配列の事前割当てをする.
事前割当は処理時間の短縮に必要.超えることがないような時間ステップ数で宣言しておく.

textscan

ヘッダー(時刻)と数値配列用で2種類の読み取り形式(FormatSpec)を用意する.

% % format
fmt_head = '%s%s%*[^\n]'; % header
fmt = [repmat('%f',[1 nx]),'\n']; % matrix
% % read
i = 1;
while ~feof(fid)
  header{i} = textscan(fid,fmt_head,1);
  dataorg{i} = cell2mat(textscan(fid,fmt,ny));
  i = i + 1;
end

数値配列を読むところでは,「cell2mat」がないと,セル配列の中にセル配列が入るので厄介.

fscanf

文字列を読み込むのにfscanfは不便なので,fgetlを使う.

% % format
fmt = [repmat('%f',[1 nx*ny]),'\n'];
% % read
i = 1;
while ~feof(fid)
  header{i} = fgetl(fid);
  dataorg{i} = fscanf(fid,fmt,[nx ny])';
  i = i + 1;
end

"[nx ny]"で読みその後転置しなければ,ファイルの配置通りに読めないことに注意.
この場合,fmtの「'\n'(=改行コード)」は超重要.読み取り開始位置の調整をしている.

おわりに

また,textscanとfscanfの両方,読み終えた後に余分に宣言した分の空白セルを削除するため,

% % delete empty cells
header(i:end) = [];
dataorg(i:end) = [];

をしてスマートに.
この変数の格納形式だと,textscanの方が速かった.

参考


Front page   Edit Diff Attach Copy Rename Reload   New List of pages Search Recent changes   Help   RSS of recent changes
Last-modified: 2017-06-08 (Thu) 05:07:41 (2513d)