Como: Consulta do maior arquivo ou arquivos em uma árvore de diretório (LINQ)

Este exemplo mostra cinco consultas relacionadas ao tamanho do arquivo em bytes:

  • Como recuperar o tamanho em bytes do arquivo maior.

  • Como recuperar o tamanho em bytes do arquivo menor.

  • Como recuperar o FileInfo arquivo de objeto de maior ou menor do que uma ou mais pastas em uma pasta raiz especificada.

  • Como recuperar uma seqüência como, por exemplo, os 10 maiores arquivos.

  • Como os arquivos de pedidos em grupos com base em seu tamanho de arquivo em bytes, ignorando arquivos menores que um tamanho especificado.

Exemplo

O exemplo a seguir contém cinco consultas separadas que mostram como consultar e arquivos de grupo, dependendo do seu tamanho de arquivo em bytes. Você pode modificar facilmente esses exemplos para basear a consulta alguma outra propriedade da FileInfo objeto.

Module QueryBySize
    Sub Main()

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

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

        ' Return the size of the largest file
        Dim maxSize = Aggregate aFile In fileList Into Max(GetFileLength(aFile))

        'Dim maxSize = fileLengths.Max
        Console.WriteLine("The length of the largest file under {0} is {1}", _
                          root, maxSize)

        ' Return the FileInfo object of the largest file
        ' by sorting and selecting from the beginning of the list
        Dim filesByLengDesc = From file In fileList _
                              Let filelength = GetFileLength(file) _
                              Where filelength > 0 _
                              Order By filelength Descending _
                              Select file

        Dim longestFile = filesByLengDesc.First

        Console.WriteLine("The largest file under {0} is {1} with a length of {2} bytes", _
                          root, longestFile.FullName, longestFile.Length)

        Dim smallestFile = filesByLengDesc.Last

        Console.WriteLine("The smallest file under {0} is {1} with a length of {2} bytes", _
                                root, smallestFile.FullName, smallestFile.Length)

        ' Return the FileInfos for the 10 largest files
        ' Based on a previous query, but nothing is executed
        ' until the For Each statement below.
        Dim tenLargest = From file In filesByLengDesc Take 10

        Console.WriteLine("The 10 largest files under {0} are:", root)

        For Each fi As System.IO.FileInfo In tenLargest
            Console.WriteLine("{0}: {1} bytes", fi.FullName, fi.Length)
        Next

        ' Group files according to their size,
        ' leaving out the ones under 200K
        Dim sizeGroups = From file As System.IO.FileInfo In fileList _
                         Where file.Length > 0 _
                         Let groupLength = file.Length / 100000 _
                         Group file By groupLength Into fileGroup = Group _
                         Where groupLength >= 2 _
                         Order By groupLength Descending

        For Each group In sizeGroups
            Console.WriteLine(group.groupLength + "00000")

            For Each item As System.IO.FileInfo In group.fileGroup
                Console.WriteLine("   {0}: {1}", item.Name, item.Length)
            Next
        Next

        ' 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.
    ' In this particular case, it is safe to ignore the exception.
    Function GetFileLength(ByVal fi As System.IO.FileInfo) As Long
        Dim retval As Long
        Try
            retval = fi.Length
        Catch ex As FileNotFoundException
            ' If a file is no longer present,
            ' just return zero bytes. 
            retval = 0
        End Try

        Return retval
    End Function
End Module
class QueryBySize
{
    static void Main(string[] args)
    {
        QueryFilesBySize();
        Console.WriteLine("Press any key to exit");
        Console.ReadKey();
    }

    private static void QueryFilesBySize()
    {
        string startFolder = @"c:\program files\Microsoft Visual Studio 9.0\";

        // 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);

        //Return the size of the largest file
        long maxSize =
            (from file in fileList
             let len = GetFileLength(file)
             select len)
             .Max();

        Console.WriteLine("The length of the largest file under {0} is {1}",
            startFolder, maxSize);

        // Return the FileInfo object for the largest file
        // by sorting and selecting from beginning of list
        System.IO.FileInfo longestFile =
            (from file in fileList
             let len = GetFileLength(file)
             where len > 0
             orderby len descending
             select file)
            .First();

        Console.WriteLine("The largest file under {0} is {1} with a length of {2} bytes",
                            startFolder, longestFile.FullName, longestFile.Length);

        //Return the FileInfo of the smallest file
        System.IO.FileInfo smallestFile =
            (from file in fileList
             let len = GetFileLength(file)
             where len > 0
             orderby len ascending
             select file).First();

        Console.WriteLine("The smallest file under {0} is {1} with a length of {2} bytes",
                            startFolder, smallestFile.FullName, smallestFile.Length);

        //Return the FileInfos for the 10 largest files
        // queryTenLargest is an IEnumerable<System.IO.FileInfo>
        var queryTenLargest =
            (from file in fileList
             let len = GetFileLength(file)
             orderby len descending
             select file).Take(10);

        Console.WriteLine("The 10 largest files under {0} are:", startFolder);

        foreach (var v in queryTenLargest)
        {
            Console.WriteLine("{0}: {1} bytes", v.FullName, v.Length);
        }


        // Group the files according to their size, leaving out
        // files that are less than 200000 bytes. 
        var querySizeGroups =
            from file in fileList
            let len = GetFileLength(file)
            where len > 0
            group file by (len / 100000) into fileGroup
            where fileGroup.Key >= 2
            orderby fileGroup.Key descending
            select fileGroup;


        foreach (var filegroup in querySizeGroups)
        {
            Console.WriteLine(filegroup.Key.ToString() + "00000");
            foreach (var item in filegroup)
            {
                Console.WriteLine("\t{0}: {1}", item.Name, item.Length);
            }
        }
    }

    // This method is used to swallow the possible exception
    // that can be raised when accessing the FileInfo.Length property.
    // In this particular case, it is safe to swallow the exception.
    static long GetFileLength(System.IO.FileInfo fi)
    {
        long retval;
        try
        {
            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;
    }

}

Para retornar a conclusão de um ou mais FileInfo objetos, primeiro a consulta deve examinar cada um dos dados de origem e, em seguida, classificá-los pelo valor de sua propriedade Length. Em seguida, ele pode retornar um único ou a seqüência com comprimento maior. Use First para retornar o primeiro elemento na lista. Use Take<TSource> para retornar o primeiro n o número de elementos. Especifique uma ordem de classificação decrescente para colocar os elementos de menores no início da lista.

A consulta chama um método separado para obter o tamanho do arquivo em bytes para consumir a exceção de possível que será gerada no caso em que um arquivo foi excluído em outro thread no período de tempo desde a FileInfo objeto foi criado na chamada para GetFiles. Até mesmo por meio de FileInfo objeto já foi criado, a exceção pode ocorrer porque um FileInfo objeto irá tentar atualizar seu Length propriedade usando o tamanho mais atual em bytes na primeira vez que a propriedade for acessada. Colocando esta operação em um bloco try-catch fora da consulta, seguimos a regra de evitar operações de consultas podem causar efeitos colaterais. Em geral, ótimo deve ter cuidado ao consumir exceções, para certificar-se de que um aplicativo não é deixado em um estado desconhecido.

Compilando o código

  • Criar um Visual Studio o projeto que se destina a .NET Framework versão 3.5. O projeto tem uma referência a System.Core.dll e um using diretiva (C#) ou Imports instrução (Visual Basic) para o namespace System. LINQ por padrão.

  • Copie este código em seu projeto.

  • Pressione F5 para compilar e executar o programa.

  • Pressione qualquer tecla para sair da janela do console.

Programação robusta

Para operações de consulta intensivo sobre o conteúdo de vários tipos de documentos e arquivos, considere o uso de O Windows Desktop Search engine.

Consulte também

Conceitos

LINQ para Objetos

LINQ e os diretórios de arquivos