Параллельное LINQ UnauthorizedAccessException при агрегации результатов - PullRequest
0 голосов
/ 11 марта 2019

Я ищу параллельно, используя 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.FileSystemEnumerableIterator 1.AddSearchableDirsToStack(SearchData localSearchData) at System.IO.FileSystemEnumerableIterator 1.MoveNext () в System.Linq.Parallel.SelectManyQueryOperator 3.SelectManyQueryOperatorEnumerator 1.MoveNext (TOutput & currentElement, Pair 2& currentKey) at System.Linq.Parallel.PipelineSpoolingTask 2.SpoolingWork () в System.Linq.Parallel.SpoolingTaskBase.Work () в System.Linq.Parallel.QueryTask.BaseWork (объект не используется) в System.Linq.Parallel.QueryTask. <> C. <. Cctor> b__10_0 (объект o) в System.Threading.Tasks.Task.InnerInvoke () в System.Threading.Tasks.Task.Execute () --- Конец внутреннего исключения трассировка стека --- в System.Linq.Parallel.QueryTaskGroupState.QueryEnd (Boolean userInitiatedDispose) в System.Linq.Parallel.AsynchronousChannelMergeEnumerator 1.MoveNextSlowPath() at System.Linq.Parallel.AsynchronousChannelMergeEnumerator 1.MoveNext ()
в System.Linq.Parallel.QueryOpeningEnumerator 1.MoveNext() at System.Linq.Enumerable.<UnionIterator>d__67 1.MoveNext () в System.Linq.Enumerable.Count [TSource] (источник IEnumerable`1)

Ответы [ 2 ]

0 голосов
/ 29 марта 2019
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;
    }
}
0 голосов
/ 11 марта 2019

Похоже, что путь C: \ Windows \ appcompat \ Programs запрещает программе создавать файлы.Это можно решить, добавив дополнительные разрешения в самой папке.

Как добавить разрешение в папку вручную

...