如何遍历 Erlang 中的目录以仅获取文件夹?

How to walk through directory in Erlang to take only folders?

-module(tut).
-export([main/0]).

main() -> 

    folders("C:/Users/David/test/").
    

folders(PATH) ->
    {_,DD} = file:list_dir(PATH),
    A = [{H,filelib:is_dir(PATH ++ H)}|| H <-DD],
    % R is a list of all folders inside PATH
    R = [PATH++X|| {X,Y} <- A, Y =:= true],
    io:fwrite("~p~n", [R]),
    case R of
        [] -> ok;
        % How call again folders function with the first element of the list?
        % And save the result in some kind of structure 
    end.

抱歉这个初学者问题,但我对 Erlang 还是个新手。我想知道如何再次调用该函数,直到将结果保存在一种列表、元组或结构中...

喜欢:

  [
    {"C:/Users/David/test/log", 
      {"C:/Users/David/test/log/a", "C:/Users/David/test/log/b"}},
    {"C:/Users/David/test/logb", 
      {"C:/Users/David/test/logb/1", "C:/Users/David/test/logb/2","C:/Users/David/test/logb/3"}},
 ]  

几件事:

  1. 这2个调用可以简化。
A = [{H,filelib:is_dir(PATH ++ H)}|| H <-DD],
R = [PATH++X|| {X,Y} <- A, Y =:= true],

进入

A = [H || H <- DD, filelib:is_dir(PATH ++ H) =:= true],
  1. 在表示上,子文件夹应该是列表格式,而不是元组格式。如果它们是元组,将很难处理。 示例结构:{Folder, [Subfolder1, Subfolder2, ...]},其中 SubfolderX 将具有相同的定义和结构,递归地
  2. 文件夹就像一棵树,这里需要递归调用。希望您已经熟悉这个概念。下面是一种使用列表推导来做到这一点的方法——无论如何还有其他方法,例如通过使用 lists:foldl 函数。
folders(PATH) ->
    {_, DD} = file:list_dir(PATH), 
    A = [H || H <- DD, filelib:is_dir(PATH ++ "/" ++ H) =:= true],
    %%io:format("Path: ~p, A: ~p~n", [Path, A]), 
    case A of
        [] ->   %%Base case, i.e. folder has no sub-folders -> stop here
                {PATH, []}; 
         _ ->   %%Recursive case, i.e. folder has sub-folders -> call @folders
                {PATH, [folders(PATH ++ "/" ++ H2) || H2 <- A]}
    end.

出于一致性原因,您需要在调用主函数 时不在末尾添加正斜杠 ,因为这将添加到函数本身中。

Folders = folders("C:/Users/David/test"). %% <- without forward slash

下面的辅助函数 pretty_print 可用于可视化 Erlang 上的输出 shell

完整代码:

-export([folders/1]).
-export([main/0]).

main() -> 
    Folders = folders("C:/Users/David/test"),
    pretty_print(Folders, 0),
    ok.
    
folders(PATH) ->
    {_, DD} = file:list_dir(PATH), 
    A = [H || H <- DD, filelib:is_dir(PATH ++ "/" ++ H) =:= true], %%please note the "/" is added here
    %%io:format("Path: ~p, A: ~p~n", [Path, A]), 
    case A of
        [] ->   %%Base case, i.e. folder has no sub-folders -> stop here
                {PATH, []}; 
         _ ->   %%Recursive case, i.e. folder has sub-folders -> call @folders
                {PATH, [folders(PATH ++ "/" ++ H2) || H2 <- A]}
    end.

pretty_print(Folders, Depth) ->
    {CurrrentFolder, ListSubfolders} = Folders,
    SignTemp = lists:duplicate(Depth, "-"),
    case Depth of
        0 -> Sign = SignTemp;
        _ -> Sign = "|" ++ SignTemp
    end,
    io:format("~s~s~n", [Sign, CurrrentFolder]),
    [pretty_print(Subfolder, Depth+1) || Subfolder <- ListSubfolders].