読者です 読者をやめる 読者になる 読者になる

いろいろ備忘録日記

主に .NET 絡みのメモを公開しています。

Linq入門記-52 (補足, .NET 4.0で追加された遅延評価されるメソッド, EnumerateFiles, EnumerateDirectories, EnumerateFileSystemEntries)

C# Linq

今回は、ちょっとした補足事項です。


.NET 4.0になり、今まで存在していたメソッドの遅延評価版が追加されたクラスが
いくつかあります。そのうちの一つが

System.IO.Directory

クラスで、以下のメソッドが追加されています。

  • EnumerateFiles
  • EnumerateDirectories
  • EnumerateFileSystemEntries


上記のメソッドは、従来から存在していた以下のメソッドの遅延評価版です。

  • GetFiles
  • GetDirectories
  • GetFileSystemEntries


書式は以下の通り。

public static IEnumerable<string> EnumerateFiles(
	string path
)

public static IEnumerable<string> EnumerateFiles(
	string path,
	string searchPattern
)

public static IEnumerable<string> EnumerateFiles(
	string path,
	string searchPattern,
	SearchOption searchOption
)

public static IEnumerable<string> EnumerateDirectories(
	string path
)

public static IEnumerable<string> EnumerateDirectories(
	string path,
	string searchPattern
)

public static IEnumerable<string> EnumerateDirectories(
	string path,
	string searchPattern,
	SearchOption searchOption
)

public static IEnumerable<string> EnumerateFileSystemEntries(
	string path
)

public static IEnumerable<string> EnumerateFileSystemEntries(
	string path,
	string searchPattern
)

public static IEnumerable<string> EnumerateFileSystemEntries(
	string path,
	string searchPattern,
	SearchOption searchOption
)


どのメソッドも、戻り値がIEnumerableになっています。
遅延評価されるということは、LINQで処理しやすいということです。


今までだと、例えばGetFilesメソッドは内部で合致する情報のコレクションを
構築してから値を返してくれていました。つまり、内容を列挙する場合
完全にコレクションが完成するまで待つ必要がありました。


EnumerableFilesメソッドの場合は、コレクションが完成する前に列挙を始める事が
可能です。LINQを利用すると、whereで必要な情報のみに絞り込んだりするのも楽です。


以下、サンプルです。
このサンプルでは、それぞれのメソッドで列挙処理が開始されるまでの
時間を計測して表示しています。

    #region LinqSamples-49
    public class LinqSamples49 : IExecutable
    {
        public void Execute()
        {
            //
            // Directory.EnumerateFilesメソッドは、従来までの
            // Directory.GetFilesメソッドと同じ動作するメソッドである。
            //
            // 違いは、戻り値がIEnumerable<string>となっており
            // 遅延評価される。
            //
            // GetFilesメソッドの場合は、全リストを構築してから
            // 戻り値が返却されるので、コレクションが構築されるまで
            // 待機する必要があるが、EnumerateFilesメソッドの場合は
            // コレクション全体が返される前に、列挙可能である。
            //
            // EnumerateDirectoriesメソッド及びEnumerateFileSystemEntriesメソッドも上記と同様。
            //
            var path    = @"c:\windows";
            var filter  = @"*.exe";
            var watch   = Stopwatch.StartNew();
            var elapsed = string.Empty;

            //
            // EnumerateFiles.
            //
            var query = from   file in Directory.EnumerateFiles(path, filter, SearchOption.AllDirectories)
                        select file;
            
            foreach (var item in query)
            {
                if (watch != null)
                {
                    watch.Stop();
                    elapsed = watch.Elapsed.ToString();
                    watch = null;
                }
                
                //Console.WriteLine(item);
            }
            
            Console.WriteLine("================== EnumereteFiles             : {0} ==================", elapsed);
            
            //
            // EnumerateDirectories.
            //
            watch   = Stopwatch.StartNew();
            elapsed = string.Empty;
            
            query = from   directory in Directory.EnumerateDirectories(path)
                    select directory;
            
            foreach (var item in query)
            {
                if (watch != null)
                {
                    watch.Stop();
                    elapsed = watch.Elapsed.ToString();
                    watch = null;
                }
                
                //Console.WriteLine(item);
            }
            
            Console.WriteLine("================== EnumerateDirectories       : {0} ==================", elapsed);
            
            //
            // EnumerateFileSystemEntries.
            //
            watch   = Stopwatch.StartNew();
            elapsed = string.Empty;
            
            query = from   directory in Directory.EnumerateFileSystemEntries(path)
                    select directory;
            
            foreach (var item in query)
            {
                if (watch != null)
                {
                    watch.Stop();
                    elapsed = watch.Elapsed.ToString();
                    watch = null;
                }
                
                //Console.WriteLine(item);
            }
            
            Console.WriteLine("================== EnumerateFileSystemEntries : {0} ==================", elapsed);

            //
            // GetFiles.
            //
            watch   = Stopwatch.StartNew();
            elapsed = string.Empty;
            
            var files = Directory.GetFiles(path, filter, SearchOption.AllDirectories);
            
            foreach (var item in files)
            {
                if (watch != null)
                {
                    watch.Stop();
                    elapsed = watch.Elapsed.ToString();
                    watch = null;
                }
                
                //Console.WriteLine(item);
            }
            
            Console.WriteLine("================== GetFiles                   : {0} ==================", elapsed);

            //
            // GetDirectories.
            //
            watch   = Stopwatch.StartNew();
            elapsed = string.Empty;
            
            var dirs = Directory.GetDirectories(path);
            
            foreach (var item in dirs)
            {
                if (watch != null)
                {
                    watch.Stop();
                    elapsed = watch.Elapsed.ToString();
                    watch = null;
                }
                
                //Console.WriteLine(item);
            }
            
            Console.WriteLine("================== GetDirectories             : {0} ==================", elapsed);

            //
            // GetFileSystemEntries.
            //
            watch   = Stopwatch.StartNew();
            elapsed = string.Empty;
            
            var entries = Directory.GetFileSystemEntries(path);
            
            foreach (var item in entries)
            {
                if (watch != null)
                {
                    watch.Stop();
                    elapsed = watch.Elapsed.ToString();
                    watch = null;
                }
                
                //Console.WriteLine(item);
            }
            
            Console.WriteLine("================== GetFileSystemEntries       : {0} ==================", elapsed);
        }
    }
    #endregion


実行結果は以下の通りです。

  ================== EnumereteFiles             : 00:00:00.0031096 ==================
  ================== EnumerateDirectories       : 00:00:00.0004081 ==================
  ================== EnumerateFileSystemEntries : 00:00:00.0002966 ==================
  ================== GetFiles                   : 00:00:02.4642173 ==================
  ================== GetDirectories             : 00:00:00.0024564 ==================
  ================== GetFileSystemEntries       : 00:00:00.0036865 ==================

================================
過去の記事については、以下のページからご参照下さい。