如何:查询一组文件夹中的总字节数 (LINQ)

此示例演示如何检索指定文件夹及其所有子文件夹中的所有文件所使用的总字节数。

示例

Sum 方法添加在 select 子句中选择的所有项的值。 您可以轻松修改此查询以检索指定目录树中的最大或最小文件,方法是调用 Min``1Max``1 方法,而不是 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;
    }
}

如果您只需要统计特定目录树中的字节数,则可以更高效地实现此目的,而无需创建 LINQ 查询,因为该查询会引发创建列表集合作为数据源的系统开销。 随着查询复杂度的增加,或者当您必须对同一数据源运行多个查询时,LINQ 方法的有用性也会随之增加。

查询调用至单独的方法来获取文件长度。 它这样做的目的是,抑制在以下情形下可能引发的异常:在对 GetFiles 的调用中创建 FileInfo 对象后在其他线程上删除该文件。 虽然已创建了 FileInfo 对象,但仍会发生异常,因为 FileInfo 对象将尝试使用第一次访问其 Length 属性时的最新长度刷新此属性。 通过将此操作放在查询外的 try-catch 块中,该代码遵循了避免在查询中执行可引发副作用的操作的规则。 通常,在抑制异常时必须格外谨慎,确保没有将应用程序置于未知状态。

编译代码

  • 创建面向 .NET Framework 3.5 版的 Visual Studio 项目。 默认情况下,该项目具有对 System.Core.dll 的引用以及针对 System.Linq 命名空间的 using 指令 (C#) 或 Imports 语句 (Visual Basic)。 在 C# 项目中,添加 System.IO 命名空间的 using 指令。

  • 将此代码复制到您的项目。

  • 按 F5 编译并运行程序。

  • 按任意键退出控制台窗口。

可靠编程

若要对多种类型的文档和文件的内容执行大量查询操作,请考虑使用 Windows Desktop Search(Windows 桌面搜索)引擎。

请参见

概念

LINQ to Objects

LINQ 和文件目录