Share via


Cómo: Agrupar archivos por extensión (LINQ)

En este ejemplo se muestra cómo se puede usar LINQ para realizar operaciones avanzadas de agrupación y ordenación en listas de archivos o carpetas. También muestra cómo desplazarse por los resultados página a página en la ventana de la consola utilizando los métodos Skip``1 y Take``1.

Ejemplo

La consulta siguiente muestra cómo agrupar el contenido de un árbol de directorios especificado por la extensión de archivo.

Module GroupByExtension
    Public Sub Main()

        ' Root folder to query, along with all subfolders. 
        Dim startFolder As String = "C:\program files\Microsoft Visual Studio 9.0\VB\" 

        ' Used in WriteLine() to skip over startfolder in output lines. 
        Dim rootLength As Integer = startFolder.Length

        'Take a snapshot of the folder contents 
        Dim dir As New System.IO.DirectoryInfo(startFolder)
        Dim fileList = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories)

        ' Create the query. 
        Dim queryGroupByExt = From file In fileList _
                          Group By file.Extension.ToLower() Into fileGroup = Group _
                          Order By ToLower _
                          Select fileGroup

        ' Execute the query. By storing the result we can 
        ' page the display with good performance. 
        Dim groupByExtList = queryGroupByExt.ToList()

        ' Display one group at a time. If the number of  
        ' entries is greater than the number of lines 
        ' in the console window, then page the output. 
        Dim trimLength = startFolder.Length
        PageOutput(groupByExtList, trimLength)

    End Sub 

    ' Pages console diplay for large query results. No more than one group per page. 
    ' This sub specifically works with group queries of FileInfo objects 
    ' but can be modified for any type. 
    Sub PageOutput(ByVal groupQuery, ByVal charsToSkip)

        ' "3" = 1 line for extension key + 1 for "Press any key" + 1 for input cursor. 
        Dim numLines As Integer = Console.WindowHeight - 3
        ' Flag to indicate whether there are more results to diplay 
        Dim goAgain As Boolean = True 

        For Each fg As IEnumerable(Of System.IO.FileInfo) In groupQuery
            ' Start a new extension at the top of a page. 
            Dim currentLine As Integer = 0

            Do While (currentLine < fg.Count())
                Console.Clear()
                Console.WriteLine(fg(0).Extension)

                ' Get the next page of results 
                ' No more than one filename per page 
                Dim resultPage = From file In fg _
                                Skip currentLine Take numLines

                ' Execute the query. Trim the display output. 
                For Each line In resultPage
                    Console.WriteLine(vbTab & line.FullName.Substring(charsToSkip))
                Next 

                ' Advance the current position
                currentLine = numLines + currentLine

                ' Give the user a chance to break out of the loop
                Console.WriteLine("Press any key for next page or the 'End' key to exit.")
                Dim key As ConsoleKey = Console.ReadKey().Key
                If key = ConsoleKey.End Then
                    goAgain = False 
                    Exit For 
                End If 
            Loop 
        Next 
    End Sub 
End Module
class GroupByExtension
{
    // This query will sort all the files under the specified folder 
    //  and subfolder into groups keyed by the file extension. 
    private static void Main()
    {
        // Take a snapshot of the file system. 
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\Common7";

        // Used in WriteLine to trim output lines. 
        int trimLength = startFolder.Length;

        // Take a snapshot of the file system.
        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(startFolder);

        // This method assumes that the application has discovery permissions 
        // for all folders under the specified path.
        IEnumerable<System.IO.FileInfo> fileList = dir.GetFiles("*.*", System.IO.SearchOption.AllDirectories);

        // Create the query. 
        var queryGroupByExt =
            from file in fileList
            group file by file.Extension.ToLower() into fileGroup
            orderby fileGroup.Key
            select fileGroup;

        // Display one group at a time. If the number of  
        // entries is greater than the number of lines 
        // in the console window, then page the output.
        PageOutput(trimLength, queryGroupByExt);
    }

    // This method specifically handles group queries of FileInfo objects with string keys. 
    // It can be modified to work for any long listings of data. Note that explicit typing 
    // must be used in method signatures. The groupbyExtList parameter is a query that produces 
    // groups of FileInfo objects with string keys. 
    private static void PageOutput(int rootLength,
                                    IEnumerable<System.Linq.IGrouping<string, System.IO.FileInfo>> groupByExtList)
    {
        // Flag to break out of paging loop. 
        bool goAgain = true;

        // "3" = 1 line for extension + 1 for "Press any key" + 1 for input cursor.
        int numLines = Console.WindowHeight - 3;

        // Iterate through the outer collection of groups. 
        foreach (var filegroup in groupByExtList)
        {
            // Start a new extension at the top of a page. 
            int currentLine = 0;

            // Output only as many lines of the current group as will fit in the window. 
            do
            {
                Console.Clear();
                Console.WriteLine(filegroup.Key == String.Empty ? "[none]" : filegroup.Key);

                // Get 'numLines' number of items starting at number 'currentLine'. 
                var resultPage = filegroup.Skip(currentLine).Take(numLines);

                //Execute the resultPage query 
                foreach (var f in resultPage)
                {
                    Console.WriteLine("\t{0}", f.FullName.Substring(rootLength));
                }

                // Increment the line counter.
                currentLine += numLines;

                // Give the user a chance to escape.
                Console.WriteLine("Press any key to continue or the 'End' key to break...");
                ConsoleKey key = Console.ReadKey().Key;
                if (key == ConsoleKey.End)
                {
                    goAgain = false;
                    break;
                }
            } while (currentLine < filegroup.Count());

            if (goAgain == false)
                break;
        }
    }
}

El resultado de este programa puede ser largo, dependiendo de los detalles del sistema de archivos local y del valor en que se haya establecido startFolder. Para habilitar la presentación de todos los resultados, este ejemplo muestra cómo recorrer los resultados página a página. Las mismas técnicas se pueden aplicar a aplicaciones Windows y web. Observe que, debido a las páginas de códigos y los elementos de un grupo, se requiere un bucle foreach anidado. Existe lógica adicional para calcular la posición actual en la lista y para permitir al usuario detener la paginación y salir del programa. En este caso determinado, la consulta de paginación se ejecuta contra los resultados de la consulta original almacenados en memoria caché. En otros contextos, como LINQ to SQL, no se requiere tal almacenamiento en caché.

Compilar el código

  • Cree un proyecto de Visual Studio que tenga como destino la versión 3.5 de .NET Framework. De manera predeterminada, el proyecto incluye una referencia a System.Core.dll y una directiva using (C#) o una instrucción Imports (Visual Basic) para el espacio de nombres System.Linq. En los proyectos de C#, agregue una directiva using para el espacio de nombres System.IO.

  • Copie este código en el proyecto.

  • Presione F5 para compilar y ejecutar el programa.

  • Presione cualquier tecla para salir de la ventana de consola.

Programación eficaz

Cuando realice operaciones de consulta intensivas sobre el contenido de múltiples tipos de documentos y archivos, considere el uso del motor de Windows Desktop Search.

Vea también

Conceptos

LINQ to Objects

LINQ y directorios de archivos