%% -*- coding: utf-8 -*- %% @doc ファイル名の一部を指定してファイルの操作. %% %% ディレクトリのリスト(検索パス)と拡張子(接尾辞)のリストに基づき %% 実在するファイルを探す(find)、開く(open)、読む(read)。 -module(findf_lib). -export([find_file/3, open_file/3, read_file/3]). % -compile(export_all). %% @headerfile "../include/findf_types.hrl" -include("../include/findf_types.hrl"). %% @doc ファイル名の一部から、 %% ディレクトリ・リストと拡張子リストをもとに、 %% 実在するファイルを探す. %% %% @spec (Name::string(), Dirs::[string()], Exts::[string()]) %% -> string() %% @throws file_error() find_file(_Name, [], _Exts) -> % 探すべき場所がない throw(enoent); % POSIXエラーコード find_file(Name, [Dir | RestDirs], Exts) -> case find_file_within(Name, Dir, Exts) of not_found -> find_file(Name, RestDirs, Exts); FilePath -> FilePath end. %% @doc 単一のディレクトリ内で、 %% 拡張子リストをもとに、 %% 実在するファイルを探す. %% (内部的関数なので、戻り値not_foundを使用). %% %% @spec (string(), string(), Exts::[string()]) %% -> not_found | string() find_file_within(_Name, _Dir, []) -> not_found; find_file_within(Name, Dir, [Ext | RestExts]) -> FilePath = filename:join(Dir, string:concat(Name, Ext)), case filelib:is_regular(FilePath) of true -> FilePath; false -> find_file_within(Name, Dir, RestExts) end. %% @type file_function() = function(). %% ファイル名文字列をただ1つの引数とするファイル操作関数. %% 実際には、file:open/1 と file:read_file/1 . %% @spec (string(), [string()], [string()], file_function()) %% -> any() %% @throws file_error() find_file_and_do(Name, Dirs, Exts, Fun) -> FilePath = find_file(Name, Dirs, Exts), case Fun(FilePath) of {ok, Value} -> Value; {error, Reason} -> throw(Reason) end. %% @doc find_file/3 で見つかったファイルをオープンする. %% @spec (string(), [string()], [string()]) -> pid() %% @throws file_error() open_file(Name, Dirs, Exts) -> find_file_and_do(Name, Dirs, Exts, fun (X) -> file:open(X, [read]) end). %% @doc find_file/3 で見つかったファイルを一括リードして、 %% 内容をバイナリとして返す. %% @spec (string(), [string()], [string()]) -> binary() %% @throws file_error() read_file(Name, Dirs, Exts) -> find_file_and_do(Name, Dirs, Exts, fun (X) -> file:read_file(X) end).