如何在Erlang中遍历目录以只取文件夹?

pobjuy32  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(158)
-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"}},
 ]
qnyhuwrf

qnyhuwrf1#

Few things:

  1. These 2 calls can be simplified.
A = [{H,filelib:is_dir(PATH ++ H)}|| H <-DD],
R = [PATH++X|| {X,Y} <- A, Y =:= true],

into

A = [H || H <- DD, filelib:is_dir(PATH ++ H) =:= true],
  1. In terms of representation, sub-folders should be in list format, not tuple. It will be difficult to work with if they were tuples. Sample structure: {Folder, [Subfolder1, Subfolder2, ...]} , where SubfolderX will have the same definition and structure, recursively.
  2. Folders are like tree, so need to have recursive call here. Hope you are already familiar with the concept. Below is one way to do it using list comprehension - there are other ways anyway, e.g. by using lists:foldl function.
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.

For consistency reason, you need to call the main function without a forward slash at the end, as this will be added in the function itself.

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

A helper function pretty_print below can be used to visualize the output on the Erlang shell
Full code:

-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].

相关问题