【MATLAB】指定フォルダ内のファイルを検索して処理をする

#はじめに
何らかの処理をすべきファイルが大量にあって，一つ一つ手作業で処理をするのは大変である．
指定したフォルダ内の指定した拡張子のファイルを一括で処理したい．

今回はサンプルとして，
**指定したフォルダとそのサブフォルダ内の全てのWAVファイルを検索し，一つ一つのファイルを開いて，時間波形を描いてPNGで保存する**
という処理をMATLABで作っていく．

その他細かい話として，
**PNGの保存先は元のWAVと同じとし，ファイル名は「元のWAVファイル名.png」とする**
**処理中はプロセスバーを表示する**
とする．

#ファイルを検索する
```matlab:

rootDir = uigetdir(pwd, '分析するディレクトリを指定してください');
if(rootDir==0)
    disp('処理を終了します');
    return
end

% カレントディレクトリをバッファ
origDir = pwd;

% カレントディレクトリを変更
cd(rootDir);

% カレントディレクトリとサブディレクトリを検索
fileList = dir('**/*.WAV');

% カレントディレクトリを戻す
cd(origDir);
```


##フォルダ選択ダイアログ
```matlab:
rootDir = uigetdir(pwd, '分析するディレクトリを指定してください');
```
でフォルダ選択ダイアログが出てきて，`rootDir`に指定したフォルダのフルパスが入る．
なお，ダイアログをキャンセルで閉じた場合は`rootDir`には`0`が入る．

![dialog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/3283c8bf-e536-d5b9-5990-a4de674049d9.png)


##ファイルリストの取得
```matlab:
fileList = dir('**/*.WAV'); % で指定したフォルダとサブフォルダを検索
% もしくは
fileList = dir('*.WAV'); % と打つと指定したフォルダだけを検索する
```
`fileList`は以下のようなフィールド**など**が入っている構造体である．

| フィールド名       | 説明 |  
|:--------------|:---------------|
| name           | ファイル名またはフォルダ名 |
| folder         | ファイルまたはフォルダのフルパス |

構造体の詳細は　[フォルダーの内容の一覧表示 -MATLAB dir- MathWorks](https://jp.mathworks.com/help/matlab/ref/dir.html) を参照．


#ファイルを一つ一つ処理する


```matlab:

% １つ１つファイルを処理していく
for n = 1:length(fileList)
    % ファイルのフルパスを取得
    fullpath = fullfile(fileList(n).folder, fileList(n).name);
    % メインの処理
    sampleSaveGraph(fullpath);
end
```

##ファイルのフルパスの取得
```matlab:
fullpath = fullfile('C:\aaa\bbb', 'ccc.txt')
```
と打つと，`fullpath`に`'C:\aaa\bbb\ccc.txt'`が入る．

```matlab:
fullpath = ['C:\aaa\bbb' '\' 'ccc.txt'];
```
でもいいと思うけど，Linuxだとファイル区切り文字が`'/'`になるので，`fullfile`を使ったほうがマルチプラットフォームに対応していて捗るらしい．


##メインの処理
`sampleSaveGraph`は自作の関数で，引数にWAVファイルのフルパスを入れると時間波形を作成してグラフを保存してくれる．
実装は↓みたいな感じ．

```matlab:sampleSaveGraph.m
function sampleSaveGraph(fullpath)
% WAVを開く
[y, Fs] = audioread(fullpath);

% グラフを描く
N = length(y);
t = ((1:N)-1)/Fs;
h = figure('WindowState','minimized');
plot(t, y);
xlim([0, t(end)]);
ylim([-1, 1]);
[filepath ,name, ext] = fileparts(fullpath);

% グラフタイトルはWAVファイル名とする
title([name, ext],'Interpreter','none');

xlabel('時間[秒]');
ylabel('振幅');

% 保存するファイルのフルパスを生成
filename = fullfile(filepath,[name, '.png']);
% ファイルを保存
saveas(h, filename);

close(h);
end
```

![chirp_10-100Hz_0_8_5s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/107d45f8-a15d-8ab1-a669-c9cfed68991b.png)
上記のような画像が保存される．

###Figureを最小化状態で立ち上げ
```matlab:
h = figure('WindowState','minimized');
```
とすると，最小化した状態のFigureウィンドウを立ち上げてくれるらしい．
そのまま立ち上げちゃうとプロセスバーが隠れて見えなくなっちゃうので，最小化で処置をした．

###ファイル名をグラフのタイトルにつける
```matlab:
[filepath ,name, ext] = fileparts(fullpath);
title([name, ext],'Interpreter','none');
```
でファイル名をタイトル表示する．
!['Interpreter'オプション無しの場合](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/caf23a67-01d7-29a0-15e2-c95af42eb9f8.png)
titleにInterpreterオプションをつけないと，ファイル名にアンダースコアがあった場合に下付き文字と判定されて上記画像のように表示されるので注意．

#プロセスバーを表示
```matlab:
% プロセスバーを立ち上げる
h = waitbar(0, waitBarText(0, length(fileList)));

% １つ１つファイルを処理していく
for n = 1:length(fileList)
    
    % メインの処理
    
    % プロセスバーを更新
    waitbar(n/length(fileList), h, waitBarText(n, length(fileList)));
end
% プロセスバーを閉じる
close(h);

function s = waitBarText(n, total)
s = sprintf('Please wait...[%d/%d]', n, total);
end
```
`waitbar`の第一引数には0～1の実数が入る．
![waitbar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/2f7d4209-cb3b-60ce-0f85-52b293f4fe9f.png)
上記のようなプロセスバーが出てくる．



#処理全体

```matlab:sample_search_files_script.m

clc
clear all
close all

rootDir = uigetdir(pwd, '分析するディレクトリを指定してください');
if(rootDir==0)
    disp('処理を終了します');
    return
end

% カレントディレクトリをバッファ
origDir = pwd;
% カレントディレクトリを変更
cd(rootDir);
% カレントディレクトリとサブディレクトリを検索
fileList = dir('**/*.WAV');
% カレントディレクトリを戻す
cd(origDir);

% プロセスバーを表示
h = waitbar(0, waitBarText(0, length(fileList)));

% １つ１つファイルを処理していく
for n = 1:length(fileList)
    % ファイルのフルパスを取得
    fullpath = fullfile(fileList(n).folder, fileList(n).name);
    % メインの処理
    sampleSaveGraph(fullpath);
    % プロセスバーを更新
    waitbar(n/length(fileList), h, waitBarText(n, length(fileList)));
end

close(h);
disp('処理が完了しました．');

function s = waitBarText(n, total)
s = sprintf('Please wait...[%d/%d]', n, total);
end
```

##実行結果
###実行前
![folder01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/a1421f4e-61ee-1026-a768-5330a90af508.png)
試しにWAVファイルを4個用意した．(内1個は新しいフォルダー内に保存)
###実行後
![folder02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373168/c6a44a52-782c-62b5-a120-2fa75d07513e.png)
期待通りに，画像が保存された．