【问题标题】:Parallel LINQ UnauthorizedAccessException when Aggregating results聚合结果时出现并行 LINQ UnauthorizedAccessException
【发布时间】:2019-08-01 10:59:15
【问题描述】:

我正在使用LINQ 并行搜索以查找模式匹配文件。

public class ParallelLinq
{
    public IList<string> SearchFolders = new List<string>
    {
        @"C:\Windows" //can be multiple
    };

    protected virtual IEnumerable<string> GetFiles(string path, string[] searchPatterns, SearchOption searchOption = SearchOption.AllDirectories)
    {
        return searchPatterns.AsParallel()
            .SelectMany(searchPattern =>
            {
                try
                {
                    return Directory.EnumerateFiles(path, searchPattern, searchOption);
                }
                catch (Exception ex) //catch UnauthoizedException/IOExceptions
                {
                    return Enumerable.Empty<string>();
                }
            });
    }

    public IEnumerable<string> Find(IList<string> patterns)
    {
        var testResultFiles = Enumerable.Empty<string>();

        if (!SearchFolders.Any() || !patterns.Any())
        {
            return testResultFiles;
        }

        testResultFiles = SearchFolders.AsParallel().Aggregate(testResultFiles, (current, folder) => current.Union(GetFiles(folder, patterns.ToArray())));

        return testResultFiles;
    }
}

但是,当我尝试评估我遇到的值时,System.UnauthorizedAccessException: Access to the path 'C:\Windows\appcompat\Programs' is denied.

var plinq = new ParallelLinq();
var res = plinq.Find(new List<string> { "*.dll" });
Console.WriteLine("Linq Count: " + res.Count());

虽然这些异常是意料之中的,但我们如何才能捕捉到它们并继续前进?

完全例外:

未处理的异常:System.AggregateException:一个或多个错误 发生了。 ---> System.UnauthorizedAccessException: 访问路径 'C:\Windows\appcompat\Programs' 被拒绝。在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
在 System.IO.FileSystemEnumerableIterator1.AddSearchableDirsToStack(SearchData localSearchData) at System.IO.FileSystemEnumerableIterator1.MoveNext() 在 System.Linq.Parallel.SelectManyQueryOperator3.SelectManyQueryOperatorEnumerator1.MoveNext(TOutput& currentElement, Pair2& currentKey) at System.Linq.Parallel.PipelineSpoolingTask2.SpoolingWork() 在 System.Linq.Parallel.SpoolingTaskBase.Work() 在 System.Linq.Parallel.QueryTask.BaseWork(对象未使用)在 System.Linq.Parallel.QueryTask.c.<.cctor>b__10_0(Object o) at System.Threading.Tasks.Task.InnerInvoke() 在 System.Threading.Tasks.Task.Execute() --- 内部异常结束 堆栈跟踪 --- 在 System.Linq.Parallel.QueryTaskGroupState.QueryEnd(布尔 userInitiatedDispose) 在 System.Linq.Parallel.AsynchronousChannelMergeEnumerator1.MoveNextSlowPath() at System.Linq.Parallel.AsynchronousChannelMergeEnumerator1.MoveNext()
在 System.Linq.Parallel.QueryOpeningEnumerator1.MoveNext() at System.Linq.Enumerable.<UnionIterator>d__671.MoveNext() 在 System.Linq.Enumerable.Count[TSource](IEnumerable`1 source)

【问题讨论】:

  • 所以你没有发现错误?不清楚您是在问是否可以优化它,还是在遇到拒绝访问错误时它根本不起作用
  • @MichaelRandall 它不起作用。它正在抛出 Exception 并返回零结果
  • Directory.EnumerateFiles 返回 IEnumerable,因此“延迟”序列,并且稍后在序列物化时抛出异常(在枚举器的 MoveNext 处)。请使用此问题遍历子文件夹并避免无法访问的子文件夹:stackoverflow.com/questions/172544/…

标签: c# linq exception plinq


【解决方案1】:

似乎路径“C:\Windows\appcompat\Programs”正在阻止程序创建文件。可以通过在文件夹本身中添加额外的权限来解决。

How to add permission to folder manually

【讨论】:

    【解决方案2】:
    public class ParallelLinq
    {
        public IList<string> SearchFolders = new List<string>
        {
            @"C:\Windows" //can be multiple
        };
    
        private static string[] TryGetTopDirectories(string path)
        {
            try
            {
                return Directory.GetDirectories(path, "*", SearchOption.TopDirectoryOnly);
            }
            catch
            {
                return new string[0];
            }
        }
    
        private static IEnumerable<string> GetSubfolders(string path, SearchOption searchOption)
        {
            if (searchOption == SearchOption.TopDirectoryOnly)
            {
                return TryGetTopDirectories(path);
            }
            else
            {
                var topFolders = TryGetTopDirectories(path);
                return topFolders.Concat(
                    topFolders.SelectMany(subFolder => GetSubfolders(subFolder, searchOption)));
            }
        }
    
        protected virtual ParallelQuery<string> GetFiles(string path, string[] searchPatterns, SearchOption searchOption = SearchOption.AllDirectories)
        {
            return GetSubfolders(path, searchOption).AsParallel()
                .SelectMany(subfolder =>
                {
                    try
                    {
                        return searchPatterns.SelectMany(searchPattern => Directory.EnumerateFiles(subfolder, searchPattern)).ToArray();
                    }
                    catch (Exception ex) //catch UnauthoizedException/IOExceptions
                    {
                        return Enumerable.Empty<string>();
                    }
                });
        }
    
        public IEnumerable<string> Find(IList<string> patterns)
        {
            var testResultFiles = Enumerable.Empty<string>();
    
            if (!SearchFolders.Any() || !patterns.Any())
            {
                return testResultFiles;
            }
    
            testResultFiles = SearchFolders.AsParallel().Aggregate(testResultFiles, (current, folder) => current.Union(GetFiles(folder, patterns.ToArray())));
    
            return testResultFiles;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-02
      • 2019-05-02
      • 2014-02-19
      • 1970-01-01
      • 2020-08-20
      相关资源
      最近更新 更多