5

これは、これを実装する際のベストプラクティスについての質問です。

FileSystemWatcherファイルとフォルダに対するユーザーの変更について通知する必要があるがあります。サブディレクトリも監視されます。同じディレクトリで、私のプログラムも時々変更されます。FileSystemWatcherこれらのプログラム変更のイベントを検出したくありません。

私の最初の実装は、予想されるイベントを追加できるリストでした。ファイルシステムイベントを取得したら、リストを確認し、存在する場合は無視します。これはあまり堅牢に聞こえませんが、機能しているようです。

今、私は本当の問題を検出しました:
D:はによって監視されていFileSystemWatcherます。
次のような2つのフォルダーがあります。D:\ folder1 \ folder2
ここで、アプリケーションでfolder1(folder2を含む)を削除します。そこで、削除リストにD:\folder1を追加しました。それから私はのようなものを呼びますDirectory.Delete(@"D:\folder1", true)。今、私はfolder1が例外を超えて(なぜ)削除できないことに気づきました。リストから削除エントリを削除しましたが、folder2はすでに削除されており、彼のFileSystemEventを取得しています。したがって、D:\ folder1\folder2のFileSystemイベントを取得します。私のプログラムは、ユーザーがこのフォルダーを削除し、間違ったことをしていると考えています。

私は今いくつかのアイデアを持っていました:

1.)すべてのファイルとすべてのフォルダを独自に削除して、フォルダを再帰的に削除します。これで、すべてのサブフォルダーを取得し、独自のリストエントリを提出します。私はすでにそれを実装しましたが、それは非常に非常に遅いです。

FileSystemWatcher2.)私のリストを時代遅れにするために賢いフィルターを入れるより良い方法があるかもしれませんか?

3.)すべてを削除できる場合にのみ、ディレクトリツリーを削除できる可能性があります。したがって、失敗した場合でもすべてがあり、そうでない場合はすべてが削除されます。これは私にとって最もエレガントな解決策のようですが、これが可能かどうかさえわかりませんか?

4.)私のソフトウェアですべてのファイルとフォルダを排他的にロックすることは可能ですか?これで問題がなければ、1つの削除コマンドですべてを削除できるはずです。

私は他の追加の解決策も受け入れています。

1を編集して、より明確にします。

フォルダに対するユーザーアクションのみを「表示」したい。ここで自分のプログラムから物事を操作する場合、このイベントを見たくありません。

私の実装では、フォルダーがロックされていて削除できない場合、サブフォルダーのイベントを取得します。

私は英語を母国語としないので、英語で説明するのはそれほど簡単ではありません;)。

編集2:

FileSystemWatcher5.)定義されたプロセスからのすべてのイベントをフィルタリングすることは可能ですか?

4

3 に答える 3

2

私は最近、まさにこの種のことをしました。秘訣は、リストにフォルダ名があることを「リスト」に認識させ、削除イベントが予想される場合はそのフォルダ内のすべてのイベントを破棄し、フォルダ自体の場合にのみ予測リストから削除することです。

FileSystemWatcherただし、警告する必要があります。連続して発生するイベントが多すぎると、バッファがいっぱいになるという問題が発生する可能性があります。これが行われると、イベントが発生しError、多数のイベントを通知できなくなります。予測リストがイベントの受信時にアイテムを削除すると、バッファオーバーフローが原因で無視しようとしたイベントが受信されなかったという理由だけで、将来のイベントを無視するリスクがあります。アイテムがリストから削除されることはないため、非常に大きくなる可能性もあります。

これを確実に行う方法はまだ見つかりませんが、FileSystemWatchersバッファーのサイズを最大に設定して、ある程度軽減することができます。

編集:また非常に重要:戻ってくるイベントは別のスレッドで行われます(ハンドラーが、またはISynchronizeInvokeなどの実装するオブジェクト上にあり、/に設定した場合を除きます。これは、方法に非常に注意する必要があることを意味します潜在的な競合状態を考慮して、リストを維持します。私はまだこれに苦労しています。私のコードは、エラーイベントを受信すると予測リストをフラッシュしますが、イベントを処理するまでに、エラー以降の他の変更イベントはすでに発生しています。解雇されて処理され、それはすべきでないものを洗い流します。ControlFormSynchronizingObjectControlForm

于 2011-02-11T09:48:14.400 に答える
1

バッファオーバーフローについて。これを解決する最善の方法は、別のスレッドのイベントに応答して作業を行うことです。私はこのようにします

// Queue of changed paths.
private readonly Queue<string> mEventQueue = new Queue<string>();

// add this as handler for filesystemwatcher events
public void FileSystemEvent(object source, FileSystemEventArgs e) {
    lock (mEventQueue) {
        if (!mEventQueue.Contains(e.FullPath)) {
            mEventQueue.Enqueue(e.FullPath);
            Monitor.Pulse(mEventQueue);
        }
    }
}

// start this on another thread
public void WatchLoop() {
    string path;
    while (true) {
        lock (mEventQueue) {
            while (mEventQueue.Count == 0)
                Monitor.Wait(mEventQueue);
            path = mEventQueue.Dequeue();
            if (path == null)
               break;
        }
        // do whatever you want to do
     }
}

そうすれば私はイベントを見逃すことはありません

于 2011-02-11T11:19:29.110 に答える
0

これが私の問題の解決策です。

削除コマンドの場合:

2つのリストを実装しました。1つはファイルの削除用で、もう1つはフォルダーの削除用です。

ファイルリストエントリにはタイムアウトがありません。ファイルを削除する場合はリストエントリを作成し、予期される削除イベントが発生した場合は以前と同じようにエントリを削除します。

フォルダリストエントリには、作成後にタイムアウトはありません。特別な方法で、1秒後にタイムアウトするように手動で命令できます。フォルダを削除する場合は、deleteFolderリストエントリを追加します。このフォルダまたはファイルまたはサブフォルダまたはサブフォルダファイルからのすべての削除イベントは、このフォルダ削除エントリのために無視されます。削除が終了した後、deleteFolderエントリのタイムアウトを準備します。削除が例外をスローする場合、私は同じことをします。したがって、1秒後にすべてのイベントを取得することを期待しています。したがって、deleteコマンドが機能するかどうかにかかわらず、すべてのイベントを無視しています。この後、deleteFolderリストエントリが削除されます。

制限事項:1。すべての削除イベントは、削除が行われてから1秒以内に発生する必要があります。2.次のようなフォルダを削除することはできません。フォルダの
削除(完了)
フォルダの作成をもう一度
1秒未満待ってフォルダを
削除します(フォルダリストの削除エントリのタイムアウトが完了していません)

非常に複雑な場合でも、これが誰かに役立つことを願っています^^

于 2011-02-16T10:28:38.587 に答える