Hatena::Grouperlang

檜山正幸のErlang未確認情報 RSSフィード

 | 

2009-06-02 (火)

コマンドラインなら1行なのに、、、

| 10:58

とあるディレクトリから下に、サイズ1メガ(1024*1024 = 1048576 ≒ 1000000)以上のファイルがあるかどうかを調べる必要があった。

$ find the/dir -type f -size +1000000c -print

で出来た。

が、なぜか(なぜだ?)Erlangでも書いてみようと思って、無駄に丁寧に書いた。あー無駄だ。

100> check_size:traverse("the/dir", fun check_size:check_size/4, [1000000]).

↑で、先のfindコマンドとほぼ同じ。

%% -*- coding: utf-8 -*-

-module(check_size).
-compile(export_all).

% @doc ファイルの種類を返す.
% @spec (string()) -> (not_exit | dir | regular | special)
file_type(Filename) ->
  case filelib:is_file(Filename) of
    false ->
      not_exist;
    true ->
      case filelib:is_dir(Filename) of
        true ->
          dir;
        false ->
          % regularとspecialの区別はあんまり当てにならないみたい
          case filelib:is_regular(Filename) of
            true ->
              regular; 
            false ->
              special
          end
      end
  end.

% @equiv traverse(TopDir, Action, [])
traverse(TopDir, Action) ->
  traverse(TopDir, Action, []).

% @doc 起点となるディレクトリから再帰的にディレクトリツリーをたどり、
% 各ファイルに対して指定されたアクションを実行する.
%
% == アクション関数の仕様 ==
% <dl>
% <dt>第1引数</dt><dd>ディレクトリ名</dd>
% <dt>第2引数</dt><dd>ファイルベース名</dd>
% <dt>第3引数</dt><dd>ファイルのタイプ (not_exit | dir | regular | special)</dd>
% </dl>
% 
% 他に追加の引数をいくつでも付けてよい. 
% 追加引数は、リストにまとめて traverse の第3引数に渡す.


% @spec (string(), function(), [any()]) -> ok
traverse(TopDir, Action, MoreArgs) ->
  {ok, Names} = file:list_dir(TopDir),
  lists:foreach(fun (Name) -> 
                    do_action(TopDir, Name, Action, MoreArgs)
                end,
                Names).

% @doc 関数として渡されたアクションを、
% 指定のディレクトリとファイル名(basename)に対して実行する.
% @spec (string(), string(), function(), [any()]) -> ok
do_action(Dir, Name, Action, MoreArgs) ->
  Filename = filename:join(Dir, Name),
  Type = file_type(Filename),
  Fullargs = [Dir, Name, Type | MoreArgs],
  case Type of
    dir ->
      apply(Action, Fullargs),
      traverse(Filename, Action, MoreArgs);
    _Other ->
      apply(Action, Fullargs),
      ok
  end.

% @doc traverseのアクション関数、ファイルサイズのチェック.
% @spec (string(), string(), atom(), number()) -> ok
check_size(Dir, Name, Type, Limit) ->
  File = filename:join(Dir, Name),
  case Type of
    regular ->
      Size = filelib:file_size(File),
      if
        Size >= Limit ->
          io:format("!! ~s ~p~n", [File, Size]);
        true ->
          ok
      end;
    dir ->
      io:format("[~s]~n", [File]);
    special ->
      ok
  end.

 |