指定ディレクトリ以下のファイル名リストの作成

年末はがりがりErlang勉強中.アキュムレータを使えるようになってきてから,だいぶ関数型脳になってきたっぽい.相変わらず楽しい言語である.


指定されたディレクトリ以下を走査して,ファイル名のリストを作成するコードを書いた.

list_dir_all (Dir) ->
    list_dir_all(Dir, []).

list_dir_all (Dir, Acc0) ->
    {ok, FileList} = file:list_dir(Dir),
    lists:foldl( fun(F, Acc) ->
                         FilePath = string:concat(string:concat(Dir, "/"), F),

                         case file_type(FilePath) of
                             regular -> [FilePath|Acc];
                             directory ->
                                 Acc ++ list_dir_all(FilePath, Acc);
                             _ -> error
                         end
                 end,
                 Acc0, FileList).

使えるようになったばかりのlists:foldl大活躍.


少し困ったことに気がつく.複数階層になってファイル数が多いようなディレクトリを対象にするとヒープ領域が溢れてしまったよ,というエラーメッセージと共にerlangシェルが落ちてしまう.

Crash dump was written to: erl_crash.dump
eheap_alloc: Cannot allocate 1425410620 bytes of memory (of type "old_heap").

再帰処理による弊害なのか.でも,foldl使って末尾再帰にしているしなぁ.
わかる人には一瞬でわかるんだろうけれど,原因はまだわかっていない.


指定ディレクトリ以下のファイル名を「リスト」で必要なことってほとんどないなぁ...フツウにディレクトリ走査しながら関数を適用すればリストを作成するコストもかからないし.

ということに,ここまで書いて気がついた.
ちょっとした変更で済むので,書いてみた.

foreach_file_all (Func, Dir) ->
    {ok, FileList} = file:list_dir(Dir),
    lists:foreach( fun(F) ->
                           FilePath = string:concat(string:concat(Dir, "/"), F),
                           case file_type(FilePath) of
                               regular -> Func(FilePath);
                               directory -> foreach_file_all(Func, FilePath);
                               _ -> error
                           end
                   end,
                   FileList).