2013-10-24 108 views
4

我有一個測試程序,應該循環在C:下的所有文件。它在遇到「Doc​​uments and Settings」文件夾時就會死亡。我想忽略錯誤並繼續循環播放其餘文件。問題是foreach,所以把try/catch圍繞foreach將導致循環退出。並且在foreach之後放一個try/catch永遠不會觸發(因爲拋出異常,foreach)。有什麼辦法可以忽略異常並繼續處理循環?如何忽略異常並繼續處理foreach循環?

下面的代碼:

static void Main(string[] args) 
{ 
    IEnumerable<string> files = Directory.EnumerateFiles(@"C:\", "*.*", 
           SearchOption.AllDirectories); 
    foreach (string file in files) // Exception occurs when evaluating "file" 
     Console.WriteLine(file); 
} 
+0

這可以幫助你,http://msdn.microsoft.com/en-us/library/dd997370.aspx – terrybozzio

+1

無論你做什麼,確保你捕獲特定的異常,而不僅僅是'Exception'。 –

+2

這裏有一個類似的問題http://stackoverflow.com/questions/2559064/is-there-a-way-of-recover-from-an-exception-in-directory-enumeratefiles –

回答

1

你可能會或得到一個UnauthorizedAccessException因爲有些文件是隱藏file.Since你處理字符串(從enumeratefiles)的系統,而不是fileinfos或DirectoryInfo的對象我改寫了這個以滿足您的設計:

第一個加法這2個成員變量:

private static Dictionary<DirectoryInfo, List<string>> DirectoryTree = new Dictionary<DirectoryInfo, List<string>>(); 
private static List<string> logger = new List<string>(); 

然後把這個方法:

static void RecursiveSearch(string root) 
{ 
    string[] files = null; 
    string[] subDirs = null; 

    // First, process all the files directly under this folder 
    try 
    { 
     files = Directory.EnumerateFiles(root).ToArray(); 
    } 
    catch (UnauthorizedAccessException e) 
    { 
     logger.Add(e.Message); 
    } 
    catch (System.IO.DirectoryNotFoundException e) 
    { 
     Console.WriteLine(e.Message); 
    } 

    if (files != null) 
    { 

      DirectoryTree.Add(new DirectoryInfo(root), files.ToList()); 
      subDirs = Directory.GetDirectories(root); 

      foreach (string dir in subDirs) 
      { 
       RecursiveSearch(dir); 
      } 
    } 
} 

然後在主你怎麼稱呼它,比如s o:

RecursiveSearch(@"c:\"); 

在您的DirectoryTree詞典和列表記錄器將被填充後。

-3
static void Main(string[] args) 
{ 
    IEnumerable<string> files = Directory.EnumerateFiles(@"C:\", "*.*", 
          SearchOption.AllDirectories); 
    foreach (string file in files) // Exception occurs when evaluating "file" 
    { 
     try 
     { 
      Console.WriteLine(file); 
     } 
     Catch(Exception ex) 
     { 
     } 
    } 
} 
+1

這不是在這裏拋出異常的控制檯寫入;它是迭代器。此外,像這樣的空捕獲所有捕獲塊是非常糟糕的做法。 – Servy

3

的問題是,IEnumerable<string>表現懶洋洋地,(有點像流)。 foreachfiles接收一個接一個的字符串,所以只有當它請求問題目錄時,枚舉器纔會崩潰。

//should now crash here instead 
List<string> files = Directory.EnumerateFiles(@"C:\", "*.*", 
          SearchOption.AllDirectories).ToList(); 

我認爲你需要找到一種方法來files轉換成一個枚舉集,由files手動獲取每個項目,並做一個try/catch圍繞:(您可以通過調用ToList()或類似這樣的事情證實了這一點從枚舉的實際讀取

編輯:。克里斯和servy在評論好點,你可能不應該亂用枚舉所有它拋出一個異常後,試着在你的查詢更保守文件可能是最簡單的解決方案。

+0

同樣的問題。一旦你遇到了一個例外情況,即枚舉器可能不再處於可用狀態。與包裝整個「foreach」循環沒有什麼不同。 – Servy

+0

@DavidD:做得比我更好,更正確。 ;-)手動獲取枚舉器可能不會有幫助,因爲一旦拋出異常,你可能不想被它搞亂。在這裏做更明智的事情可能是確保你不要讓它列舉無效的文件... – Chris

+0

@Servy和克里斯是好點。可能的解決辦法是通過不要求驅動器上的每個文件實際工作。 –

2

沒有有效的方法來處理這種情況。如果迭代器本身在試圖獲取下一個項目時拋出異常,那麼在此之後它將不能提供該項目;它不再處於「有效」狀態。一旦拋出異常,你就完成了該迭代器。

此處唯一的選擇是不使用此方法查詢整個驅動器。也許你可以編寫自己的迭代器來手動遍歷驅動器,以便無法遍歷的項目被更優雅地跳過。

所以,要做這個手動遍歷。我們可以用廣義含Traverse方法,可以穿越任何樹開出(非遞歸,以便更好地有效地處理深棧):

public static IEnumerable<T> Traverse<T>(
    this IEnumerable<T> source 
    , Func<T, IEnumerable<T>> childrenSelector) 
{ 
    var stack = new Stack<T>(source); 
    while (stack.Any()) 
    { 
     var next = stack.Pop(); 
     yield return next; 
     foreach (var child in childrenSelector(next)) 
      stack.Push(child); 
    } 
} 

現在我們只要抓住根本,穿越它,並使用獲得的方法不會拋出異常的子目錄:

var root = new DirectoryInfo("C:\\"); 
var allFiles = new[] { root }.Traverse(dir => GetDirectoriesWithoutThrowing(dir)) 
    .SelectMany(dir => GetFilesWithoutThrowing(dir)); 

得到子目錄可以開始作爲像這樣的方法,但可能需要充實:

private static IEnumerable<DirectoryInfo> GetDirectoriesWithoutThrowing(
    DirectoryInfo dir) 
{ 
    try 
    { 
     return dir.GetDirectories(); 
    } 
    catch (Exception)//if possible catch a more derived exception 
    { 
     //TODO consider logging the exception 
     return Enumerable.Empty<DirectoryInfo>(); 
    } 
} 

請注意,您可以稍微玩一下這個特定的部分。即使你不能獲取其他的子目錄,你也許能夠在這裏得到一些子目錄,你可能需要調整錯誤處理等。獲取文件版本將基本相同,但只需要GetFiles

+0

正如在一般意見中提到的http://stackoverflow.com/questions/2559064/is-there-a-way-of-recover-from-an-exception- in-directory-enumeratefiles基本上是同一個問題,並且有一些代碼幾乎完全符合你的建議。以爲我會在這裏更明確地提到,因爲這似乎是目前最可能接受的答案(並且在鏈接中進行編輯可能是好的)。 – Chris

+1

@Chris這個解決方案並不可怕,但它熱切地搜索整棵樹,並不完全儘可能清潔。我加入了我自己的解決方案。 – Servy

+0

甚至比引用其他東西更好。 ;-)良好的代碼。 – Chris