簡體   English   中英

如何忽略異常並繼續處理foreach循環?

[英]How to ignore an exception and continue processing a foreach loop?

我有一個測試程序,它應該遍歷C:下的所有文件。 當它到達“Documents and Settings”文件夾時它會死掉。 我想忽略錯誤並繼續循環其余文件。 問題是,異常拋出foreach ,所以把一個try/catch周圍foreach會導致循環退出。 並把一個try/catchforeach永遠不會觸發(因為異常拋出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);
}

問題是IEnumerable<string>表現得懶散,(有點像流)。 foreachfiles接受一個接一個的字符串,因此只有當它請求問題目錄時,枚舉器才會崩潰。 (您可以通過調用ToList()或類似的東西來確認:

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

我認為您需要找到一種方法將files轉換為枚舉集合,方法是從files手動獲取每個項目,並對枚舉器的實際讀取執行try / catch。

編輯: chris和servy在評論中有很好的分數。 在拋出異常之后,你可能根本不應該弄亂枚舉器。 嘗試在文件查詢中更加保守可能是最簡單的解決方案。

沒有有效的方法來處理這種情況。 如果迭代器本身在嘗試獲取下一個項目時拋出異常,那么它就不會在此之后為您提供該項目; 它不再處於“有效”狀態。 一旦拋出異常,你就完成了迭代器。

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

所以,要做這個手動遍歷。 我們可以從一個可以遍歷任何樹的通用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

您可能會收到UnauthorizedAccessException,因為某些文件是隱藏的或系統文件。因為您正在處理字符串(來自enumeratefiles)而不是fileinfos或directoryinfo對象,所以我重寫了這個以適合您的設計:

首先添加這兩個成員變量:

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);
          }
     }
}

然后在Main中你這樣稱呼它:

RecursiveSearch(@"c:\");

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

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)
        {
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM