【问题标题】:Recursing directories only goes one file deep递归目录只深入一个文件
【发布时间】:2015-03-31 15:10:16
【问题描述】:

我有以下代码:

find_info(File) ->
    case file:read_file_info(File) of
        {ok, Facts} -> 
            case Facts#file_info.type of
                directory -> directory;
                regular -> regular
            end;
        {error,Reason} -> exit(Reason)
    end.

find_files(Dir,Flag,Ending,Acc) -> 
    case file:list_dir(Dir) of
        {ok,A} -> find_files_helper(A,Dir,Flag,Acc,Ending);
        {_,_} -> Acc
    end. 

find_files_helper([H|Tail],Dir,Flag,Acc,Ending) ->
    A = find_info(filename:absname_join(Dir,H)),
    case A of
        directory -> 
            case Flag of
                true -> 
                    find_files(filename:absname_join(Dir,H),Flag,Ending,Acc ++ find_files_helper(Tail,Dir,Flag,Acc,Ending));
                false -> find_files_helper(Tail,Dir,Flag,Acc,Ending)
            end;
        regular -> 
        case filename:extension(H) of
            Ending -> find_files_helper(Tail,Dir,Flag,[to_md5_large(H)] ++ Acc, Ending);
            _ -> find_files_helper(Tail,Dir,Flag,Acc,Ending)
        end;
        {error,Reason} -> exit(Reason)
    end;
find_files_helper([],_,_,Acc,_) -> Acc.

但是,每当我运行 find_files/4 时,程序在崩溃之前只会深入一个文件。 假设我有以下目录

home/
   a/
     ser.erl
   b/
   c/
file.erl
file2.erl

运行时我会得到file.erlfile2.erlser.erl 的md5。但是,如果目录如下所示:

home/
   a/
     ser.erl
     back.erl
   b/
   c/
file.erl
file2.erl

然后整个程序崩溃。我花了几个小时寻找我的逻辑中缺少的东西,但我不知道。

我收到的错误消息是函数 p:to_md5_large/1 中的异常 enoent。

如果这里需要 md5,它是:

to_md5_large(File)  ->

        case file:read_file(File) of
            {ok, <<B/binary>>} -> md5_helper(B,erlang:md5_init());
            {error,Reason} -> exit(Reason)
        end.

md5_helper(<<A:4/binary,B>>,Acc) -> md5_helper(B,erlang:md5_update(Acc,A));
md5_helper(A,Acc) -> 
    B =     erlang:md5_update(Acc,A),
    erlang:md5_final(B).

【问题讨论】:

  • 你得到enoent,因为当你不在back.erl所在的目录中时,你将back.erl之类的文件名传递给to_md5_large。尝试传递完整的文件名。
  • @SteveVinoski 想把它作为答案?

标签: file recursion erlang


【解决方案1】:

您得到enoent 是因为当您不在back.erl 所在的目录中时,您将back.erl 之类的文件名传递给to_md5_large。尝试传递完整的文件名。你已经在find_files_helper 中调用了filename:absname_join(Dir,H),所以只需将其保存到一个变量中,然后将该变量而不是H 传递给to_md5_large

【讨论】:

    【解决方案2】:

    有一个函数可以为你做这件事:

    fold_files(Dir, RegExp, Recursive, Fun, AccIn) -> AccOut
    

    在你的情况下:

    Result = filelib:fold_files(Dir, ".*\.erl", true, fun(X,Acc) -> {ok,B} = file:read_file(X), [erlang:md5(B)|Acc] end, []).
    

    [编辑]

    @布拉:

    我没有直接回答你的问题有两个原因:

    • 第一个是,在我写答案的时候,你没有提供你得到的错误类型。对于任何语言,学习如何从错误报告中获取信息都非常重要。在 erlang 中,大多数情况下,您会在错误发生的行中获得错误类型,查看文档您将获得有关问题所在的非常有用的信息。顺便说一句,除非你想管理错误,否则我不鼓励你写这样的东西:

      case file:read_file(File) of
          {ok, <<B/binary>>} -> md5_helper(B,erlang:md5_init());
          {error,Reason} -> exit(Reason)
      end.
      

    下面的代码将做同样的事情,更短,你会得到你遇到问题的确切行号(它不是你代码中最好的例子,但它更短)

        {ok, <<B/binary>>} = file:read_file(File),
        md5_helper(B,erlang:md5_init()),
    
    • 第二个是我发现你的代码太大了,有无用的辅助函数。我认为尝试拥有简洁易读的代码很重要,并且尝试以正确的方式使用库函数。例如,您正在使用 erlang:md5:init/0、erlang:md5_update/2 和 erlang:md5_final/1 而对 erlang:md5/1 的单次调用就足够了。您使用它的方式是在您逐块获取数据时能够计算md5,这不是您的情况,并且您编写辅助函数的方式不允许使用此功能。

    我不明白你为什么想要你的代码的“部署”版本,但我建议你另一个版本,我试图遵循我的建议(直接写在 shell 中,所以它需要 R17+ 来定义递归匿名函数) :o)

    1> F = fun F(X,D,Ending) ->                                                                     
    1>   {ok,StartD} = file:get_cwd(),        %% save current directory                                    
    1>   ok = file:set_cwd(D),                %% move to the directory to explore                          
    1>   R = case filelib:is_dir(X) of                                                                
    1>     true ->                            %% if the element to analyze is a directory                                  
    1>       {ok,Files} = file:list_dir(X),   %% getits content                                       
    1>       [F(Y,X,Ending) || Y <- Files];   %% and recursively analyze all its elements             
    1>     false -> 
    1>       case filelib:is_regular(X) andalso (filename:extension(X) == Ending) of         
    1>         true ->                        %% if it is a regular file with the right extension              
    1>           {ok,B} = file:read_file(X),  %% read it                                               
    1>           [erlang:md5(B)];             %% and calculate the md5 (must be return in a list                                            
    1>                                        %% for consistancy with directory results)
    1>         false ->                                                                                
    1>           []                           %% in other cases (symlink, ...) return empty                                     
    1>       end                                                                                       
    1>   end,                                                                                        
    1>   ok = file:set_cwd(StartD),           %% restore current directory                                    
    1>   lists:flatten(R)                     %% flatten for nicer result                                       
    1> end.                                                                                          
    #Fun<erl_eval.42.90072148>
    2> Md5 = fun(D) -> F(D,D,".erl") end.
    #Fun<erl_eval.6.90072148>
    3> Md5("C:/My programs/erl6.2/lib/stdlib-2.2").
    [<<150,238,21,49,189,164,184,32,42,239,200,52,135,78,12,
       112>>,
     <<226,53,12,102,125,107,137,149,116,47,50,30,37,13,211,243>>,
     <<193,114,120,24,175,27,23,218,7,169,146,8,19,208,73,255>>,
     <<227,219,237,12,103,218,175,238,194,103,52,180,132,113,
       184,68>>,
     <<6,16,213,41,39,138,161,36,184,86,17,183,125,233,20,125>>,
     <<23,208,91,76,69,173,159,200,44,72,9,9,50,40,226,27>>,
     <<92,8,168,124,230,1,167,199,6,150,239,62,146,119,83,36>>,
     <<100,238,68,145,58,22,88,221,179,204,19,26,50,172,142,193>>,
     <<253,79,101,49,78,235,151,104,188,223,55,228,163,25,16,
       147>>,
     <<243,189,25,98,170,97,88,90,174,178,162,19,249,141,94,60>>,
     <<237,85,6,153,218,60,23,104,162,112,65,69,148,90,15,240>>,
     <<225,48,238,193,120,43,124,63,156,207,11,4,254,96,250,204>>,
     <<67,254,107,82,106,87,36,119,140,78,216,142,66,225,8,40>>,
     <<185,246,227,162,211,133,212,10,174,21,204,75,128,125,
       200,...>>,
     <<234,191,210,59,62,148,130,187,60,0,187,124,150,213,...>>,
     <<199,231,45,34,185,9,231,162,187,130,134,246,54,...>>,
     <<157,226,127,87,191,151,81,50,19,116,96,121,...>>,
     <<15,59,143,114,184,207,96,164,155,44,238,...>>,
     <<176,139,190,30,114,248,0,144,201,14,...>>,
     <<169,79,218,157,20,10,20,146,12,...>>,
     <<131,25,76,110,14,183,5,103,...>>,
     <<91,197,189,2,48,142,67,...>>,
     <<94,202,72,164,129,237,...>>,
     <<"^NQÙ¡8hÿèkàå"...>>,<<"ðÙ.Q"...>>,
     <<150,101,76,...>>,
     <<"A^ÏrÔ"...>>,<<"¹"...>>,<<...>>|...]
    4>
    

    【讨论】:

    • 我不想使用 BIF
    猜你喜欢
    • 1970-01-01
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多