• ベストアンサー

[C#]このコードはもっと速くなると思いますか?

フォルダ内の全ファイルを取得する、以下のようなコードを組んでみました。 このコードではFileInfoを配列に入れていますが、厳密には「ファイル名」「ファイルパス」「ファイルサイズ」「更新日時」を格納したリストが欲しいです。 using System; using System.Collections.Generic; using System.Diagnostics; static void Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); //windows xpを使っています DirectoryInfo di = new DirectoryInfo(@"C:\WINDOWS"); test(di); sw.Stop(); Console.WriteLine(sw.ElapsedMilliseconds); } //ファイル情報を格納する配列 static List<FileInfo> list = new List<FileInfo>(); //全ファイルの探索 static void test(DirectoryInfo di) { foreach(FileInfo fi in di.GetFiles()) list.Add(fi); foreach(DirectoryInfo ddi in di.GetDirectories()) test(ddi); } ちなみに私の環境では1000ms前後の結果になります。 このリストを取得するのに、さらにスピードアップさせる方法はあると思いますか? どんな些細な事でも良いので答えて下さるとありがたいです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

 こんばんは。  手っ取り早くは、「foreach」を「while」又は「for」に差し替える、と言った所でしょうか。  当方が書店でC#の書籍を立ち読みした際に、「foreach」は「for」と比較して実行コストがかかる、と記載されていたと記憶しています。  日本のサイトから探し出せなかったので、海外サイトになりますが、 ・「Which loop is better in performance - foreach or for or while?」  http://forums.asp.net/t/1041090.aspx  100000回ループで、  for->0.0003745秒  while->0.0003641秒  foreach->0.0009076秒  と言う計測結果が出ています。 ・「C# Foreach Loop Optimization」  http://dotnetperls.com/foreach-loop-optimization  こちらの方は、メンバ変数ではなく、ローカル変数へコピーしたものを「foreach」で使用すると僅かながらも速度が改善すると言うネタの様です。  その他のネタとしては、「FindNextFile()API」等を直接呼び出してみる、と言ったところです。  但し、P/Invokeを始め、C言語同等のプレーンな構造体を用意する必要があり、unsafeキーワードの使用も避けられそうにありません。コードもややこしくなります。  勿論、内部的にはNetFrameworkがAPIを呼び出している筈ですが、API呼び出しに到達するまでにはそれなりに時間がかかっているでしょうから、時間に余裕があれば実験してみる価値はあるかもしれません。  ツリービューにディレクトリ構造とファイルを表示する場合は、クリックされたフォルダから+2階層先まで検索して、こっそりとツリーアイテムを追加して行く事で容易に最適化が行えるのですが、ファイル名等をリストコレクションに収めて行きたいと言う事の様ですので、これ以上は打つ手なし、でしょうか。

sankaku197
質問者

お礼

多数のご提案、ありがとうございます。 残念ながら上二つは、速度アップに繋がりませんでした。 (http://ufcpp.net/study/csharp/sp_foreach.html 余談ですが上記リンク先の後ろ2行によると、配列のforeachはfor相当のコードに最適化されるようですね) FindNextFile()についてはP/Invokeという聞き慣れない単語、さらにunsafeを使うという事ですので、すみませんがお礼だけ先にするという形を取らせて貰います。 私程度の頭で理解出来るか分かりませんが、少しずつでも調べて組んでみたいと思います。 >これ以上は打つ手なし、でしょうか。 うーん、なるほどそうです。 いや十分すぎるほど参考・勉強になりました。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (2)

回答No.3

ちなみにコマンドプロンプトで dir /s C:\Windows > 適当なファイルのパス だとどれぐらいかかりますか? その時間とあまり変わらないのであればそんなに早くできないのかなぁと。

sankaku197
質問者

お礼

なるほど、その手がありましたか。 というわけで、早速試してみましたけど体感的にはあまり変わらない感じですね。 うーん、これ以上の速度アップは難しそうですね。 これを結論として締めさせて頂きます、ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

> foreach(FileInfo fi in di.GetFiles()) > list.Add(fi); の部分を list.AddRange(di.GetFiles()); に変えてみたらどうでしょうか。

参考URL:
http://msdn.microsoft.com/ja-jp/library/z883w3dc.aspx
sankaku197
質問者

お礼

回答ありがとうございます。 こんな質問に答えてくれるような奇特な人はいないだろう、と思ってたので正直嬉しいです。 しかし残念ながら速度アップには至りませんでした。 AddRangeの存在をすっかり忘れてたので、この回答を見た時の衝撃はかなりものだったんですけど。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 決まった拡張子のファイルだけ表示したい(C#)

    こんばんわ。また質問させてください。 ボタン1を押すことでリストに指定したフォルダの中身をすべて表示するプログラムが出来たのですが、このあとテキストファイルだけを表示したい場合はどうしたらいいのでしょうか? テキストファイルだけをリストに昇順で表示して、それらテキストファイルの内容をすべて連結してみたいのでご指導してくださると助かります。 連結の方法は分かりました。 private void button1_Click(object sender, System.EventArgs e) { string systemFolder = "ここにフォルダのパス"; DirectoryInfo di = new DirectoryInfo(systemFolder); // フォルダ内のファイルをリストに表示 foreach(FileInfo fi in di.GetFiles()) { listBox1.Items.Add(fi.Name); } }

  • C#)フォルダを参照したい

    こんにちわ。 フォルダを参照してその中身をリストBOXに表示したいのですが、サンプルを見つけて実行したのですがいまいち理解できなかったのでアドバイスくださると助かります。 private void button1_Click(object sender, System.EventArgs e) { string systemFolder = Environment.GetFolderPath    (Environment.SpecialFolder.System); DirectoryInfo di = new DirectoryInfo(systemFolder); foreach(FileInfo fi in di.GetFiles()) { listBox1.Items.Add(fi.Name); } } これでボタン1をクリックするとsystemフォルダの内容がリストに表示されるのですが、そもそもどこのsystemフォルダなのか分かりません・・・。 ↑のプログラムが分からず別の方法でまずフォルダ参照ダイアログの FolderBrowserDialog を使おうと思ったのですが、ツールBOXに無いのでまた困りました。 どなたか分かる方いたらご指摘お願いします。

  • C# StreamReader,StreamWriter による文字化

    C# StreamReader,StreamWriter による文字化け お世話になります。 文字化けで悩んでいます。 Visual Studio 2008 C# にて、テキストファイルからデータを読んで別のテキストファイルに そのまま書き出す(もちろん実際の運用では加工するわけですが)処理で文字化けが起こります。 そのテキストファイル自身を C# で作れば問題はないのですが、メモ帳を使って書き込んだファイルでは 文字化けが起こります。 対処方法があれば教えてください。 以下はその実験に使ったコードです。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace ConsoleApplication5 { class Program { static void Main(string[] args) { // これは正常に書き込みできました StreamWriter sw = new StreamWriter(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\test.txt"); sw.WriteLine("これはてすとです。"); sw.WriteLine("This is test."); sw.Close(); // これも正常に読み込め、書き込みもできました StreamReader sr = new StreamReader(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\test.txt"); sw = new StreamWriter(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\newtest.txt"); while (!sr.EndOfStream) { sw.WriteLine(sr.ReadLine()); } sr.Close(); sw.Close(); // 次はあらかじめメモ帳で作ったファイルを読んで、別のファイルに書き出します // これが文字化けします sr = new StreamReader(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\test2.txt"); sw = new StreamWriter(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\newtest2.txt"); while (!sr.EndOfStream) { string dat = sr.ReadLine(); sw.WriteLine(dat); Console.WriteLine(dat); } sr.Close(); sw.Close(); } } }

  • Visual Studio 2017C#

    下記のVisual Studio 2017 C# 19行目のXの定義がありません。 と出ました。 11行目で定義していると思うのですけど…。 どういうことなのか教えてください。 ご多忙のところ恐れ入りますが、ご回答のほどよろしくお願いします。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace jump25 { class Test { public int x = 10; } class Program { public static void Main(string[] args) { Test obj = new Test(); int y = object.x; Console.WriteLine(y); } } }

  • C# override

    某C#の入門書のサンプルですが、overrideがよくわかりません。 using System; using System.Collections.Generic; using System.Text; namespace PersonList {   class Person   {     public string name;     public int age;     public Person(string nam, int ag)     {       name = nam;       age = ag;     }     public override string ToString()     {       return String.Format("{0}({1})", name, age);     }   }   class Program   {     static void Main(string[] args)     {       List<Person> p = new List<Person>();       p.Add(new Person("Pochi", 3));       p.Add(new Person("Kenta", 5));       p.Add(new Person("Mari", 4));       p.Add(new Person("Wanko", 1));       p.Add(new Person("Doggy", 4));       p.ForEach(Console.WriteLine);     }   } } 1.overrideをしないと 「PersonList.Person」が出力されてしまうのですが  なぜToString()をoverrideするのかがわかりません。 2.override しないですべての内容を出力するためにはどうしたら  いいのでしょうか?

  • C# Listクラスにクラスを追加したいがエラー

    以下のようなコードを書いたのですが (A)(B)の箇所で (A) error CS1513: } が必要です。 (B) /error CS1022:型、名前空間の定義、またはファイルの終わりが必要です。 というエラーになるのですが、なにが間違っているのでしょうか。 --------------------------------------------------- using System; using System.Collections.Generic; namespace My {  class MyClass  {   public static void Main()   { // <--- (A)    public List<Book> myList = new List<Book>    {     new Book(){ title = "ABC", price = 1000 },     new Book(){ title = "DEF", price = 2000 }    };   }  }  class Book  {   //プロパティの自動実装   public string title { get; set; }   public decimal price { get; set; }  } } // <--- (B) ---------------------------------------------------

  • C# マルチスレッドにおける例外処理

    下記のようなデリゲートを利用したマルチスレッドのプログラムを組みました。 しかし、マルチスレッド内で例外がおきても、正常にプログラムが終了してしまいます。 (try-catchでも例外を捕捉できません) マルチスレッドプログラムにおいて、例外を捕捉するにはどうすれば、いいのでしょうか? using System; using System.Threading; class Class1 { delegate void delg(); public static void Main() { delg d = new delg(multi); d.BeginInvoke(new AsyncCallback(call), null); //マルチスレッド開始 System.Threading.Thread.Sleep(500); //マルチスレッドで例外を強制的に投げているので、 //ここまでたどり着く前にアプリケーションが落ちるはず。 //しかし、実際には正常終了。 Console.WriteLine("メインメソッド 正常終了"); } public static void multi() { Console.WriteLine("マルチスレッドで実行中"); throw new Exception(); //例外を強制的に投げる。 } public static void call(IAsyncResult ar) { Console.WriteLine("コールバックメソッド実行"); } }

  • C#についての質問です

    Microsoft Visual C# 2010 Express をつかって using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Console { class Program { static void Main(string[] args) { Console.WriteLine("皆様、はじめまして"); } } } と入力して.csで保存したのですが、コマンドプロンプトで 'csc' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。 とでてコンパイルできません。対応を教えてください。

  • c#のプログラムについて。

    c#のプログラムについて。 お世話になります。 c#初心者です。 下記の様なコードを記述してますが、 「 Form1.Button1.Visible == false;」の部分で 「'WindowsFormApplication1.Form1'にButton1'の定義がありません。」 と言うエラーが出てしまいます。 どの様に定義して良いのかが分からず、悩んでいます。 どなたかお教え頂きたく宜しくお願い致します。        記 using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace WindowsFormsApplication3 { static class Program { /// <summary> /// アプリケーションのメイン エントリ ポイントです。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); string result = System.Environment.MachineName; if (result == "xxxxxxx") { Form1.Button1.Visible == false; } } } }

  • OutLookのメール受信通知 (C#)

    教えてください。C#の勉強中でわからないところがあります。 [環境] C# 2.0 windowsXP Outlook2003 [内容] アプリケーションを起動後、 Outlookでメールを受信したら、アプリケーションでFormの表示のラベルを変更したいのでが、うまくいきません。教えてくださいませ。 ちなみに、下記のソースはMessageBoxで作成したものです。 MessageBoxだとうまくいくのですが・・・ using System; using System.Windows.Forms; using OutLook = Microsoft.Office.Interop.Outlook; [ソース] using System; using System.Windows.Forms; using OutLook = Microsoft.Office.Interop.Outlook; [STAThread] static void Main(string[] args) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new frmMessage());  MessageBox.Show("待機中"); MessageStand(); } /// <summary> /// OutLook待機処理 /// </summary> private static void OneSightMessageStand() { OutLook.ApplicationClass outLookApp = new OutLook.ApplicationClass(); outLookApp.NewMailEx += new OutLook.ApplicationEvents_11_NewMailExEventHandler(outLookApp_NewMailEx); } /// <summary> /// イベント処理 /// </summary> private static void outLookApp_NewMailEx(string EntryIDCollection) { MessageBox.Show("受信しました。" + EntryIDCollection, "NOTE", MessageBoxButtons.OK); # 通常ならメッセージボックスではなくイベントが発生したら、Formのラベルにメッセージを表示したい。 frmMessage objfm = new frmMessage(); objfm.label.txt = "受信しました。"; }