Compartir a través de


Cómo: Buscar el número total de bytes en un conjunto de carpetas (LINQ)

En este ejemplo se muestra cómo recuperar el número total de bytes utilizados por todos los archivos en una carpeta especificada y todas sus subcarpetas.

Ejemplo

El método Sum agrega los valores de todos los elementos seleccionados en la cláusula select. Es fácil modificar esta consulta para recuperar el archivo mayor o menor del árbol de directorios especificado mediante una llamada al método Min``1 o Max``1 en lugar de Sum.

Module QueryTotalBytes
    Sub Main()

        ' Change the drive\path if necessary. 
        Dim root As String = "C:\Program Files\Microsoft Visual Studio 9.0\VB" 

        'Take a snapshot of the folder contents. 
        ' This method assumes that the application has discovery permissions 
        ' for all folders under the specified path. 
        Dim fileList = My.Computer.FileSystem.GetFiles _
                  (root, FileIO.SearchOption.SearchAllSubDirectories, "*.*")

        Dim fileQuery = From file In fileList _
                        Select GetFileLength(file)

        ' Force execution and cache the results to avoid multiple trips to the file system. 
        Dim fileLengths = fileQuery.ToArray()

        ' Find the largest file 
        Dim maxSize = Aggregate aFile In fileLengths Into Max()

        ' Find the total number of bytes 
        Dim totalBytes = Aggregate aFile In fileLengths Into Sum()

        Console.WriteLine("The largest file is " & maxSize & " bytes")
        Console.WriteLine("There are " & totalBytes & " total bytes in " & _
                          fileList.Count & " files under " & root)

        ' Keep the console window open in debug mode
        Console.WriteLine("Press any key to exit.")
        Console.ReadKey()
    End Sub 

    ' This method is used to catch the possible exception 
    ' that can be raised when accessing the FileInfo.Length property. 
    Function GetFileLength(ByVal filename As String) As Long 
        Dim retval As Long 
        Try 
            Dim fi As New System.IO.FileInfo(filename)
            retval = fi.Length
        Catch ex As System.IO.FileNotFoundException
            ' If a file is no longer present, 
            ' just return zero bytes. 
            retval = 0
        End Try 

        Return retval
    End Function 
End Module
class QuerySize
{
    public static void Main()
    {
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\VC#";

        // Take a snapshot of the file system. 
        // This method assumes that the application has discovery permissions 
        // for all folders under the specified path.
        IEnumerable<string> fileList = System.IO.Directory.GetFiles(startFolder, "*.*", System.IO.SearchOption.AllDirectories);

        var fileQuery = from file in fileList
                        select GetFileLength(file);

        // Cache the results to avoid multiple trips to the file system. 
        long[] fileLengths = fileQuery.ToArray();

        // Return the size of the largest file 
        long largestFile = fileLengths.Max();

        // Return the total number of bytes in all the files under the specified folder. 
        long totalBytes = fileLengths.Sum();

        Console.WriteLine("There are {0} bytes in {1} files under {2}",
            totalBytes, fileList.Count(), startFolder);
        Console.WriteLine("The largest files is {0} bytes.", largestFile);

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }

    // This method is used to swallow the possible exception 
    // that can be raised when accessing the System.IO.FileInfo.Length property. 
    static long GetFileLength(string filename)
    {
        long retval;
        try
        {
            System.IO.FileInfo fi = new System.IO.FileInfo(filename);
            retval = fi.Length;
        }
        catch (System.IO.FileNotFoundException)
        {
            // If a file is no longer present, 
            // just add zero bytes to the total.
            retval = 0;
        }
        return retval;
    }
}

Si sólo es necesario contar el número de bytes de un árbol de directorios especificado, puede hacerlo de forma más eficaz sin crear una consulta LINQ, sin el esfuerzo adicional de tener que crear la colección de listas como origen de datos. La utilidad de LINQ aumenta cuanto más compleja es la consulta, o cuando es necesario ejecutar varias consultas en el mismo origen de datos.

La consulta llama a un método independiente para obtener la longitud del archivo. La razón es utilizar la posible excepción que se producirá si el archivo se eliminó en otro subproceso después de haber creado el objeto FileInfo en la llamada a GetFiles. Aunque ya se haya creado el objeto FileInfo, la excepción se puede producir igualmente si un objeto FileInfo intenta actualizar su propiedad Length con la longitud más actualizada la primera vez que se tenga acceso a la propiedad. Al incluir esta operación en un bloque try-catch fuera de la consulta, el código sigue la regla de evitar usar en las consultas operaciones que pueden tener efectos adversos. Por lo general, se deben tomar precauciones al utilizar las excepciones, para asegurarse de que una aplicación no queda en un estado desconocido.

Compilar el código

  • Cree un proyecto de Visual Studio para 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