7

多くのファイルが同時にディレクトリに追加されると、FileSystemWatcher が正しく動作しません...

ウォッチャーは、ディレクトリ内のすべてのファイルを見つけるわけではありません-ファイルが1つずつフォルダーに配置されている場合のみ-多くのファイルが同時にフォルダーにコピーされている場合ではありません...

スレッドの作成は問題の解決策ですか、それとも問題を処理する別の方法はありますか?

4

3 に答える 3

12

そのクラスのドキュメントには、その問題の詳細が記載されています。

Windows オペレーティング システムは、FileSystemWatcher によって作成されたバッファー内のファイルの変更をコンポーネントに通知します。短時間に多くの変更がある場合、バッファがオーバーフローする可能性があります。これにより、コンポーネントはディレクトリ内の変更を追跡できなくなり、一括通知のみが提供されます。InternalBufferSizeプロパティを使用してバッファーのサイズを大きくすると、ディスクにスワップ アウトできない非ページ メモリに由来するため、負荷が高くなります。そのため、ファイル変更イベントを見逃さないように、バッファーをできるだけ小さく保ちます。バッファ オーバーフローを回避するには、NotifyFilterプロパティとIncludeSubdirectoriesプロパティを使用して、不要な変更通知を除外できるようにします。

したがって、この場合、スレッドはおそらくあまり役​​に立ちません。おそらく、バッファ サイズを大きくするか (ただし、どの程度の大きさにするかは、コンピュータの速度とディスク自体に依存する可能性があります)、適切なフィルタを設定して、関心のあるファイルを制限することをお勧めします。

于 2009-10-15T13:44:59.983 に答える
1

C# は私にとって初めてで、同じ問題に 1 週​​間近く苦労しました。私はこれを持っていました:

    private void btnWatchFile_Click(object sender, EventArgs e)
    {
        //code to create a watcher and allow it to reise events...
    }

    //watcher onCreate event
    public void onCreated(object sender, FileSystemEventArgs e)
    {
        if (!updateNotifications )
        {
            stringBuilder.Remove(0, stringBuilder.Length);
            stringBuilder.Append(e.FullPath);
            stringBuilder.Append(" ");
            stringBuilder.Append(e.ChangeType.ToString());
            stringBuilder.Append("    ");
            stringBuilder.Append(DateTime.Now.ToString());
            updateNotifications = true;
        }
    }

    //timer to check the flag every X time
    private void timer_Tick(object sender, EventArgs e)
    {
        if (updateNotifications )
        {
            notificationListBox.Items.Insert(0, stringBuilder.ToString());
            updateNotifications = false;
        }
    }

タイマー間隔を 1 ミリ秒に設定しても、いくつかの新しいファイル イベントが欠落していました。notificationsListBoxイベント内の fromを更新しようとしましたonCreatedが、常に相互参照エラーが発生しました。onCreatedこれは、ウォッチャーイベントがメインメソッドスレッド以外のスレッドで実行されることが判明するまでのことでした。つまり、これが私の解決策です。

public delegate void Action()クラスの属性として含め、イベント内の fromInvokeを更新するために使用しました。次に、ピースコード:notificationsListBoxonCreated

    public void onCreated(object sender, FileSystemEventArgs e)
    {
        stringBuilder.Remove(0, stringBuilder.Length);
        stringBuilder.Append(e.FullPath);
        stringBuilder.Append(" ");
        stringBuilder.Append(e.ChangeType.ToString());
        stringBuilder.Append("    ");
        stringBuilder.Append(DateTime.Now.ToString());
        updateNotifications = true;
        Invoke((Action)(() => {notificationListBox.Items.Insert(0, stringBuilder.ToString());}));
    }

そのため、タイマーとそのコードは不要になりました。これは私にとって非常にうまく機能し、同様の状況にある人にとってもうまくいくことを願っています. よろしくお願いします!!!

于 2015-09-17T13:26:16.107 に答える
0

このようなことを試してください。

public MainWindow()
    {
        InitializeComponent();

        #region initialise FileSystemWatcher
        FileSystemWatcher watch = new FileSystemWatcher();
        watch.Path = folder;
        watch.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
        watch.Filter = ext;
        watch.Changed += new FileSystemEventHandler(OnChanged);
        watch.Created += new FileSystemEventHandler(OnChanged);
        watch.EnableRaisingEvents = true;
        #endregion

    }

 private void OnChanged(object source, FileSystemEventArgs e)
    {
        Application.Current.Dispatcher.BeginInvoke((Action)delegate
        {
          // do your work here. If this work needs more time than it can be processed, not the filesystembuffer overflows but your application will block. In this case try to improve performance here.
        }, System.Windows.Threading.DispatcherPriority.Normal);
    }
于 2012-07-04T09:01:09.313 に答える