#author("2018-07-25T19:34:40+09:00","default:Miyashita","Miyashita")
#author("2018-07-25T19:35:53+09:00","default:Miyashita","Miyashita")
*while文を使ったファイル終端までのデータ読み込み [#x9a72c1b]
一連のフォーマットがファイルの中で何回続くかわからない時に,
#codeprettify(lang-matlab){{
while ~feof(fid)
}}
を使ってファイルの最後まで読み取る(fidはfopenで開いたファイルID).~
**ファイル形式例 [#u1b0f7ed]
例として,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で方法が異なるので別々に.~
**事前作業 [#t1d5deab]
どちらも共通の作業として,
 % % preallocate
 nt_upper = 1000;
 header = cell(nt_upper,1);
 dataorg = cell(nt_upper,1);
 % % open 
 fid = fopen(filename,'r');
#codeprettify(lang-matlab){{
% % preallocate
nt_upper = 1000;
header = cell(nt_upper,1);
dataorg = cell(nt_upper,1);
% % open 
fid = fopen(filename,'r');
}}
のように,ファイルを開き配列の事前割当てをする.~
事前割当は処理時間の短縮に必要.超えることがないような時間ステップ数で宣言しておく.~
**textscan [#x37959aa]
ヘッダー(時刻)と数値配列用で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
#codeprettify(lang-matlab){{
% % 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 [#y6a69b83]
文字列を読み込むのに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
#codeprettify(lang-matlab){{
% % 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'(=改行コード)」は超重要.読み取り開始位置の調整をしている.~
**おわりに [#a030f9d7]
また,textscanとfscanfの両方,読み終えた後に余分に宣言した分の空白セルを削除するため,
 % % delete empty cells
 header(i:end) = [];
 dataorg(i:end) = [];
#codeprettify(lang-matlab){{
% % delete empty cells
header(i:end) = [];
dataorg(i:end) = [];
}}
をしてスマートに.~
この変数の格納形式だと,textscanの方が速かった.~

***参考 [#oc65d5c6]
-[[while>https://jp.mathworks.com/help/matlab/ref/while.html]]~
-[[feof>https://jp.mathworks.com/help/matlab/ref/feof.html]]~

Front page   Edit Diff Attach Copy Rename Reload   New List of pages Search Recent changes   Help   RSS of recent changes