Procedura: scorrere le directory dei file con PLINQHow to: Iterate File Directories with PLINQ

Questo esempio mostra due semplici modi per parallelizzare le operazioni su directory di file.This example shows two simple ways to parallelize operations on file directories. La prima query usa il metodo GetFiles per popolare una matrice di nomi di file in una directory e in tutte le sottodirectory.The first query uses the GetFiles method to populate an array of file names in a directory and all subdirectories. Questo metodo non restituisce alcun risultato finché non viene popolata l'intera matrice e di conseguenza può introdurre latenza all'inizio dell'operazione.This method does not return until the entire array is populated, and therefore it can introduce latency at the beginning of the operation. Tuttavia, dopo che la matrice viene popolata, PLINQ può elaborarla in parallelo molto rapidamente.However, after the array is populated, PLINQ can process it in parallel very quickly.

La seconda query usa i metodi statici EnumerateDirectories e EnumerateFiles, che iniziano a restituire risultati immediatamente.The second query uses the static EnumerateDirectories and EnumerateFiles methods which begin returning results immediately. Questo approccio può rivelarsi più veloce quando si esegue l'iterazione di alberi di directory di grandi dimensioni, anche se i tempi di elaborazione rispetto al primo esempio possono dipendere da molti fattori.This approach can be faster when you are iterating over large directory trees, although the processing time compared to the first example can depend on many factors.

Avviso

Lo scopo di questi esempi è mostrare l'utilizzo e la loro esecuzione potrebbe non essere più rapida della query LINQ to Objects sequenziale equivalente.These examples are intended to demonstrate usage, and might not run faster than the equivalent sequential LINQ to Objects query. Per altre informazioni sull'aumento di velocità, vedere Informazioni sull'aumento di velocità in PLINQ.For more information about speedup, see Understanding Speedup in PLINQ.

EsempioExample

L'esempio seguente mostra come eseguire l'iterazione di directory di file in semplici scenari quando si ha accesso a tutte le directory nell'albero, le dimensioni dei file non sono molto grandi e i tempi di accesso non sono significativi.The following example shows how to iterate over file directories in simple scenarios when you have access to all directories in the tree, the file sizes are not very large, and the access times are not significant. Questo approccio comporta un periodo di latenza all'inizio, durante la creazione della matrice di nomi di file.This approach involves a period of latency at the beginning while the array of file names is being constructed.


struct FileResult
{
    public string Text;
    public string FileName;
}
// Use Directory.GetFiles to get the source sequence of file names.
public static void FileIteration_1(string path)
{       
    var sw = Stopwatch.StartNew();
    int count = 0;
    string[] files = null;
    try
    {
        files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories);
    }
    catch (UnauthorizedAccessException e)
    {
        Console.WriteLine("You do not have permission to access one or more folders in this directory tree.");
        return;
    }

    catch (FileNotFoundException)
    {
        Console.WriteLine("The specified directory {0} was not found.", path);
    }

    var fileContents = from file in files.AsParallel()
            let extension = Path.GetExtension(file)
            where extension == ".txt" || extension == ".htm"
            let text = File.ReadAllText(file)
            select new FileResult { Text = text , FileName = file }; //Or ReadAllBytes, ReadAllLines, etc.              

    try
    {
        foreach (var item in fileContents)
        {
            Console.WriteLine(Path.GetFileName(item.FileName) + ":" + item.Text.Length);
            count++;
        }
    }
    catch (AggregateException ae)
    {
        ae.Handle((ex) =>
            {
                if (ex is UnauthorizedAccessException)
                {
                   Console.WriteLine(ex.Message);
                   return true;
                }
                return false;
            });
    }
   
    Console.WriteLine("FileIteration_1 processed {0} files in {1} milliseconds", count, sw.ElapsedMilliseconds);
    }

EsempioExample

L'esempio seguente mostra come eseguire l'iterazione di directory di file in semplici scenari quando si ha accesso a tutte le directory nell'albero, le dimensioni dei file non sono molto grandi e i tempi di accesso non sono significativi.The following example shows how to iterate over file directories in simple scenarios when you have access to all directories in the tree, the file sizes are not very large, and the access times are not significant. Questo approccio inizia a restituire risultati più rapidamente rispetto all'esempio precedente.This approach begins producing results faster than the previous example.


struct FileResult
{
    public string Text;
    public string FileName;
}

// Use Directory.EnumerateDirectories and EnumerateFiles to get the source sequence of file names.
public static void FileIteration_2(string path) //225512 ms
{
    var count = 0;
    var sw = Stopwatch.StartNew();
    var fileNames = from dir in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)
                    select dir;
  

    var fileContents = from file in fileNames.AsParallel() // Use AsOrdered to preserve source ordering
                       let extension = Path.GetExtension(file)
                       where extension == ".txt" || extension == ".htm"
                       let Text = File.ReadAllText(file)
                       select new { Text, FileName = file }; //Or ReadAllBytes, ReadAllLines, etc.
    try
    {
        foreach (var item in fileContents)
        {
            Console.WriteLine(Path.GetFileName(item.FileName) + ":" + item.Text.Length);
            count++;
        }
    }
    catch (AggregateException ae)
    {
        ae.Handle((ex) =>
            {
                if (ex is UnauthorizedAccessException)
                {
                   Console.WriteLine(ex.Message);
                   return true;
                }
                return false;
            });
    }

    Console.WriteLine("FileIteration_2 processed {0} files in {1} milliseconds", count, sw.ElapsedMilliseconds);
}

Quando si usa GetFiles, assicurarsi di avere autorizzazioni sufficienti per tutte le directory nell'albero.When using GetFiles, be sure that you have sufficient permissions on all directories in the tree. In caso contrario, verrà generata un'eccezione e non verrà restituito alcun risultato.Otherwise an exception will be thrown and no results will be returned. Quando si usa EnumerateDirectories in una query PLINQ, risulta problematico gestire le eccezioni di I/O in un modo appropriato che permetta di proseguire con l'iterazione.When using the EnumerateDirectories in a PLINQ query, it is problematic to handle I/O exceptions in a graceful way that enables you to continue iterating. Se il codice deve gestire eccezioni di I/O o di accesso non autorizzato, è consigliabile provare l'approccio descritto in Procedura: Eseguire l'iterazione di file di directory con la classe Parallel.If your code must handle I/O or unauthorized access exceptions, then you should consider the approach described in How to: Iterate File Directories with the Parallel Class.

Se la latenza di I/O costituisce un problema, ad esempio con I/O di file in una rete, provare a usare una delle tecniche di I/O asincrono descritte in Task Parallel Library e programmazione asincrona .NET Framework tradizionale e in questo post di blog.If I/O latency is an issue, for example with file I/O over a network, consider using one of the asynchronous I/O techniques described in TPL and Traditional .NET Framework Asynchronous Programming and in this blog post.

Vedere ancheSee Also

Parallel LINQ (PLINQ)Parallel LINQ (PLINQ)