2015-03-30 67 views
0

我有以下代碼:遞歸目錄只進了檔深

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. 

但是每當我運行尋找文件/ 4的程序只進了檔深崩潰之前。 說我有以下目錄

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

運行的時候我會得到的file2.erlfile.erlser.erl和MD5。但是,如果目錄看起來像這樣:

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

然後整個程序崩潰。我花了好幾個小時在我的邏輯中尋找我在這裏想念的東西,但我不知道。

我得到的錯誤消息是函數p:to_md5_large/1中的異常內容。

如果這裏需要的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). 
+0

當你不在'back.erl'所在的目錄中時,你正在獲得'enoent',因爲你將'back.erl'這樣的文件名傳遞給'to_md5_large'。嘗試傳遞完整的文件名。 – 2015-03-30 20:39:42

+0

@SteveVinoski想把它作爲答案? – Bula 2015-03-30 20:53:14

回答

1

你得到enoent,因爲你傳遞一個文件名類似back.erlto_md5_large,當你在back.erl所在的目錄不是。嘗試傳遞完整的文件名。您已在find_files_helper中調用filename:absname_join(Dir,H),因此請將其保存到變量中,並將該變量而不是H傳遞給to_md5_large

1

有一個功能,這是否對你:

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, []). 

[編輯]

@Bula:

我沒有直接回答你的問題有兩個原因:

  • 第一個是,當時我在寫我的答案,你沒有提供你得到的錯誤類型。用任何語言來學習如何從錯誤報告中獲取信息是非常重要的。在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 + for遞歸的匿名函數的定義):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> 
+0

我不想使用BIF – Bula 2015-03-30 20:49:10

+1

那裏沒有BIF嗎?這是一個奇怪的要求。 – Pascal 2015-03-30 21:00:31