方法 : 一連のフォルダの合計バイト数を問い合わせる (LINQ)

更新 : 2007 年 11 月

この例では、指定したフォルダとすべてのサブフォルダにおいて、その中に存在するすべてのファイルで使用される合計バイト数を取得する方法を示します。

使用例

Sum メソッドは、select 句で選択されたすべての項目の値を加算します。Sum の代わりに Min メソッドや Max メソッドを呼び出すことで、指定したディレクトリ ツリー内の最大または最小のファイルを取得するように、このクエリを簡単に変更できます。

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 オブジェクトが既に作成されていても、例外は発生する可能性があります。これは、Length プロパティに最初にアクセスしたときに、FileInfo オブジェクトがこのプロパティを最新の長さで更新しようとするためです。この操作をクエリの外部の try-catch ブロックに配置することで、副作用を引き起こす可能性のある操作をクエリで行わないという規則に従ったコードになります。一般に、例外を処理する場合は、アプリケーションが不明な状態にならないように最新の注意が必要です。

コードのコンパイル方法

  • .NET Framework Version 3.5 を対象とする Visual Studio プロジェクトを作成します。プロジェクトには、System.Core.dll への参照と、System.Linq 名前空間に対する using ディレクティブ (C#) または Imports ステートメント (Visual Basic) が既定で含まれます。C# プロジェクトでは、System.IO 名前空間に対する using ディレクティブを追加します。

  • コードをプロジェクト内にコピーします。

  • F5 キーを押して、プログラムをコンパイルおよび実行します。

  • 任意のキーを押して、コンソール ウィンドウを終了します。

堅牢性の高いプログラム

複数の種類のドキュメントやファイルの内容を対象に、集中的にクエリ操作を実行する場合は、Windows デスクトップ サーチ エンジンを使用することを検討してください。

参照

概念

LINQ to Objects

LINQ とファイル ディレクトリ