2011-07-13 6 views
0

シータム内の何らかのファイルを検索する小さなプログラムを作成し、検索が完了したらリストビューで結果を表示しますこのプログラムは私のフォームがフリーズして何もできません。C#を使用してシステム全体のファイルを検索するためのプログラムを実行するときにUIがフリーズする

誰かが下に、問題を解決しようとする際に助けてください、私はあなたがFindFiles機能で、かなり重いrecursive処理を行っている

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading.Tasks; 
using System.IO; 
using System.Threading; 
using System.IO.Compression; 
using System.Security.AccessControl; 


namespace SearchAndZipUtility 
{ 
    public partial class MainForm : Form 
    { 
     private string _destFolder; 
     private string _sourceToSearch = @"E:\New Books"; 
     private TaskScheduler schedular = TaskScheduler.Current; 
     private CancellationTokenSource _ct = new CancellationTokenSource(); 
     private List<string> files = new List<string>(); 
     private string _selectedFileType; 

     public MainForm() 
     { 
      InitializeComponent(); 
      toolStripStatusInfo.Visible = false; 
      btnZip.Enabled = false; 
     } 

     protected override void OnLoad(EventArgs e) 
     { 
      // bind file types to combo box 
      PopulateComboList(); 
      if (cmbFileTypes.Items.Count > 0) 
      { 
       cmbFileTypes.SelectedIndex = 0; 
      } 
     } 

     private void PopulateComboList() 
     { 
      cmbFileTypes.Items.AddRange(FileTypes.GetFileTypes()); 
     } 

     private void btnDest_Click(object sender, EventArgs e) 
     { 
      DialogResult dr = folderBrowserDialog.ShowDialog(); 

      if (dr == System.Windows.Forms.DialogResult.OK) 
      { 
       _destFolder = folderBrowserDialog.SelectedPath; 
       txtDestFolder.Text = _destFolder; 
      } 
     } 

     private void btnStartSearch_Click(object sender, EventArgs e) 
     { 
      toolStripStatusInfo.Visible = true; 
      btnStartSearch.Enabled = false; 
      fileListView.Items.Clear(); 
      fileListView.Refresh(); 
      _selectedFileType = cmbFileTypes.SelectedItem.ToString(); 

      List<Task> taskList = new List<Task>(); 
      DriveInfo[] drives = DriveInfo.GetDrives().Where(drive => drive.DriveType == DriveType.Fixed).ToArray(); 

      try 
      { 
       foreach (DriveInfo d in drives) 
       { 
        DriveInfo dInfo = d; 
        //Task searchTask = Task.Factory.StartNew(() => { Fi}, _ct.Token, TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext()); 
        Task searchTask = Task.Factory.StartNew(() => { FindFiles(dInfo.RootDirectory, ref files); } 
                      , _ct.Token, TaskCreationOptions.LongRunning 
                      , TaskScheduler.FromCurrentSynchronizationContext()); 

        System.Diagnostics.Trace.WriteLine("currently reading" + d.RootDirectory.FullName); 
        taskList.Add(searchTask); 

        searchTask.ContinueWith(PopulateResultList, TaskScheduler.FromCurrentSynchronizationContext()); 

       } 

       Task.Factory.ContinueWhenAll(taskList.ToArray(), OnSearchCompleted, _ct.Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); 

      } 
      catch (Exception ex) 
      { 
       System.Diagnostics.Trace.WriteLine(ex.Message); 
      } 
      finally 
      { 

      } 


     } 

     private void OnSearchCompleted(Task[] tasks) 
     { 
      // hide notifier label 
      toolStripStatusInfo.Visible = false; 
      btnStartSearch.Enabled = true; 
      btnZip.Enabled = true; 
      toolStripStatusLabel.Text = string.Format("Total files found: {0}", files.Count); 
     } 

     private List<string> SearchFiles() 
     { 
      // DirectoryInfo dirSource = new DirectoryInfo(_sourceToSearch); 
      _selectedFileType = cmbFileTypes.SelectedItem.ToString(); 
      return files; 
     } 

     private void FindFiles(DirectoryInfo directoryInfo, ref List<string> files) 
     { 
      FileSystemAccessRule rule = new FileSystemAccessRule(System.Security.Principal.WindowsIdentity.GetCurrent().Name, FileSystemRights.FullControl, System.Security.AccessControl.AccessControlType.Allow); 

      try 
      { 
       foreach (DirectoryInfo d in directoryInfo.GetDirectories()) 
       { 
        //d.GetAccessControl().ResetAccessRule(rule); 
        System.Diagnostics.Trace.WriteLine("currently reading> " + d.FullName); 
        FindFiles(d, ref files); 
       } 

       files.AddRange(directoryInfo.GetFiles(string.Format("*.{0}", _selectedFileType), SearchOption.AllDirectories).Select(finfo => finfo.FullName)); 
      } 
      catch (UnauthorizedAccessException excep) 
      { 
       System.Diagnostics.Trace.WriteLine(excep.Message); 
      } 
      catch (Exception e) 
      { 
       return; // MessageBox.Show(e.Message); 
      } 

     } 

     private void PopulateResultList(Task searchedTask) 
     { 
      // fill up list view 
      fileListView.Items.AddRange(files.Select(fileName => new ListViewItem { Checked = true, Text = fileName }).ToArray()); 
      toolStripStatusLabel.Text = string.Format("Total files found so far: {0}", files.Count); 
     } 

     private void btnZip_Click(object sender, EventArgs e) 
     { 

     } 
    } 
} 
+1

注: 'try/catch 'ブロックに' finally'ブロックを追加する必要はありません。空の 'finally {}'ブロックと 'finally {return; }メソッドの最後には何もしません。 –

+0

はWPFまたはWinフォームと思いますか?私はそれに応じてサンプルを更新します –

+0

私はWinFormsを使用しています... –

答えて

0

を書かれているコードです。あなたのディレクトリ構造のどこか低いところで起動しているのであれば、おそらく処理が遅いかもしれません...

あなたが何をする必要があるかによっては、これを避けることができないかもしれません。 FindFilesへの最初の呼び出しの前後にブレークポイントを入れて、それが問題の領域であるかどうか確認してください。

1

現在のタスクスケジューラ(この場合はメッセージループを使用しています)を使用してタスクを開始しています。

このように、メッセージループがそのタスクの処理を開始すると、完了するまでブロックされます。

タスクスケジューラを指定しないようにしてください。タスクスケジューラが新しいスレッドをスピンアップするはずです。

+0

こんにちはLasse、応答のために、実際に私がスケジューラを使用しない場合は、私はクロススレッドの例外を取得します。 –

+0

uiと対話するすべてのタスクにスケジューラを使用する必要があります。 findタスクはそうではないので、それらのタスクにスケジューラを指定するのではなく、uiを更新するタスクに対して行います。 –

+0

ただし、タスクスケジューラを削除して代わりにスレッドを取得すると、スレッドセーフではないため、ファイルを配置する共通リストへの参照が破損します。私のアドバイスは、突っ込みを取る前にスレッディングについて多くのことを学ぶことです。マルチスレッドは、いまだに一番難しいことの一つです。 –

0

バックグラウンドワーカー(または他のDoWork()スレッドスキーム)を設定する必要があると思われます。ここでは、役に立つかもしれない、発見できないJon Skeetのan articleがあります。

0

集中処理を

Application.DoEvents(); 

を有する任意のループ内のコードの次の行を入れてこれが複数のスレッドを使用して回避し、応答形態を維持します。ただし、ジョブの実行中にユーザーがクリックしたくないボタンを無効にしたり、再度有効にする必要があります。

スレッドは一般的に応答不能を処理するより良い方法と考えられていますが、より複雑なので、これは簡単な方法です。

DoEventsをFindFilesメソッドに追加した場合は、Factory.StartNewを削除して、各タスクに対して直接FindFilesを呼び出すことができます。

+0

Application.DoEvents()は簡単にしか見えません。最終的に、発生する可能性があるさまざまな再突入問題に取り掛かります。このような前向きな立場をとっても、コードを後で維持している人は、それを簡単に分けることができます。スレッディングも非常に難しいですが、ほとんどの開発者は、スレッドが使用されていることがわかるたびに慎重になることを学びます。 –

関連する問題