orizuru

つながる.見える.わかる IoTソリュ-ション

【C#】ファイル一覧取得速度比較

約 4 分
【C#】ファイル一覧取得速度比較

2019/03/28 コメントでご指摘いただいた部分を再計測、修正

お久しぶりです、エンジニアのMasashiです。

今回は特定のディレクトリ内に含まれているファイルの一覧を取得する際の速度比較について検証を行ってみました。
C#でファイル検索を行う際は、Directory.GetFilesメソッド、.NET Framework 4.0以降であれば
Directory.EnumerateFilesメソッドのどちらかを利用することが多いかと思います。
今回Directory.GetFilesメソッドとDirectory.EnumerateFilesメソッドではファイルの一覧を取得する際に
どの程度速度差が生まれるのかを検証してみたいと思います。

測定までの流れ

フォルダ内のファイルをサブフォルダまで含んだ状態で検索した結果を2つのメソッドで測定します。
検索のオプションにtxt形式のファイルを検索するように指定したものと検索ファイル対象に指定がないものの
2種類を用意しオプションの違いで速度差が生まれるかも測定してみます。

測定環境

  • Visual Studio 2015

対象データ

  • フォルダ直下ファイル数:10,000
  • サブフォルダ数:1,000
  • サブフォルダ内のファイル数:1,000
  • 総ファイル数:1,010,000

測定対象

  • Directory.GetFilesメソッド、オプションにtxt形式を指定
  • Directory.GetFilesメソッド、オプション指定なし
  • Directory.EnumerateFilesメソッド、オプションにtxt形式を指定
  • Directory.EnumerateFilesメソッド、オプションに指定なし

テストコード

測定結果

10回試行した結果の平均値が下記になっています。

ここをタップして表示Close
計測項目 計測時間(ms)
Directory.GetFilesメソッド、オプションにtxt形式を指定 4725.975
Directory.GetFilesメソッド、オプション指定なし 4660.758
Directory.EnumerateFilesメソッド、オプションにtxt形式を指定 3952.278
Directory.EnumerateFilesメソッド、オプションに指定なし 3171.094

上記からDirectory.GetFilesメソッドとDirectory.EnumerateFilesメソッドでのファイル取得結果には
1秒程度ですが、速度差が生まれることが測定できました。
オプションの違いで比較した場合、オプション指定なしのほうが
ファイル一覧を取得するのに若干ですが速度が速くなることがわかります。
これは、オプションが指定されている場合、*.txtに該当する名前のファイルか、txt拡張子のファイルかを判定しているために
発生する時間が速度差として生まれていると考えられます。

まとめ

今回Directory.GetFilesメソッドとDirectory.EnumerateFilesメソッドでの
ファイル取得速度について比較を行ってみましたが、はっきりと大きな速度差を見つけることはできませんでしたが、若干Directory.EnumerateFilesが速い結果となりました。
現行の環境では、ほとんどが.NET Framework 4.0以降を使用していると思いますので、
基本的にはDirectory.EnumerateFilesメソッドを使用するのが最善だと考えられます。
またオプションの有無については微々たる差ではあるので、特に気にする必要はないかと思いますが、
1形式のファイルしかフォルダ内に存在しない時のファイル名を取得したいかつ、速度を少しでも向上させたい場合は、
オプションをワイルドカードにしてもらえれば少し速度が向上することがわかりました。
普段何気なく使用している関数ですが、意外なところに違いがあったりして計測してみると
興味深い結果が得られることがあります。
これを機にC#でいろいろな性能比較を行っていただければ幸いです。

About The Author

エンジニアMasashi
C#を用いた業務系アプリの製造に従事。

Comments & Trackbacks

  • Comments ( 2 )
  • Trackbacks ( 0 )
  1. 匿名で失礼します
    技術情報の公開に敬意を表しつつも、
    幾分誤解があると思いますので、僭越ですがご連絡いたしました

    var files =
    di.GetFiles(“*”, SearchOption.AllDirectories);
    はString型の配列にファイル一覧が既に格納されています。

    対して
    var files =
    di.EnumerateFiles(“*”, SearchOption.AllDirectories);
    はIEnumerableを返すだけで、実際には何も処理を終えていません。

    実際の値の取得では、foreeachなどで使用するかと思いますが、

    http://garicchi.hatenablog.jp/entry/2014/09/12/200000
    ======================================
    MyCollection collection = new MyCollection();
    foreach (int i in collection)
    {
    Console.WriteLine(i);
    }

    これでコレクションを列挙することができます。

    foreachはコンパイル時にこんな感じになります。

    IEnumerator enumerator=collection.GetEnumerator();
    while (enumerator.MoveNext())
    {
    object obj = enumerator.Current;
    Console.WriteLine(obj.ToString());
    }
    ======================================

    内分的には、列挙型でのMoveNextメソッドの際に、
    APIなどで次のファイル名を取得しにいくことになります。
    このメソッドが実装されている目的は、DBのカーソル処理などと同様です。
    大量のメモリを消費しないよう逐次的に処理を行うことができます。

    foreachにて実際のファイル名を取得すれば、結果としてさほど差が生じないことが確認できるかと思います。

    • 上記ご指摘、誠にありがとうございます。
      おっしゃっていただきました通り、実際に何も処理を終えていない状態で計測結果を記載しておりました。

      頂きました内容をもとにブログ記事も記載を修正させていただきました。
      コメントもわかりやすき記載いただき、実際の処理イメージをきちんと認識することができました。
      どうぞ引き続きよろしくお願いいたします。

LEAVE A REPLY TO 匿名 CANCEL REPLY

*
*
* (公開されません)