C # – Prédire les événements du système de fichiers lors de la suppression d’un dossier

C’est plutôt une question de savoir quelle est la meilleure pratique pour mettre cela en œuvre.

J’ai un FileSystemWatcher qui devrait m’informer des modifications apscopes par l’utilisateur aux fichiers et aux dossiers. Les sous-répertoires sont également surveillés. Dans le même répertoire, mon programme change aussi parfois. Je ne veux pas que FileSystemWatcher détecte les événements sur ces modifications de programme.

Ma première implémentation était une liste où je peux append des événements attendus. Lorsque j’obtiens un événement de système de fichiers, je vérifie la liste et l’ignore si elle est présente. Cela ne semble pas très robuste, mais cela semblait fonctionner.

Maintenant, j’ai détecté le vrai problème:
D: est regardé par FileSystemWatcher .
J’ai deux dossiers comme ça: D: \ folder1 \ folder2
Maintenant, je veux supprimer folder1 (avec folder2) avec mon application. Donc, je mets D: \ folder1 dans ma liste de suppression. Ensuite, j’appelle quelque chose comme Directory.Delete(@"D:\folder1", true) . Maintenant, je remarque que folder1 ne peut pas être supprimé (pourquoi jamais) par une exception. Je supprime l’entrée de suppression de ma liste mais folder2 était déjà supprimé et je récupère son FileSystemEvent. Je reçois donc un événement FileSystem pour D: \ folder1 \ folder2. Mon programme pense maintenant que l’utilisateur a supprimé ce dossier et fait le mauvais choix.

J’ai eu quelques idées maintenant:

1.) Supprimez récursivement le dossier en supprimant chaque fichier et chaque dossier séparément. Avec cela, je reçois pour chaque sous-dossier et classe une propre entrée dans la liste. Je l’ai déjà implémenté mais c’est très très très lent.

2.) Peut-être existe-t-il un meilleur moyen d’avoir des filtres astucieux dans FileSystemWatcher pour rendre ma liste obsolète?

3.) Peut-être qu’il est possible de supprimer uniquement une arborescence de répertoires s’il est possible de tout supprimer. Donc, si cela échoue, j’ai toujours tout et sinon tout est supprimé. Cela semble être la solution la plus élégante pour moi, mais vous ne savez pas si cela est possible?

4.) Est-il possible de verrouiller exclusivement tous les fichiers et dossiers avec mon logiciel? Si cela se passe bien, il devrait être possible de tout supprimer avec une seule commande de suppression ou quelque chose comme ça?

Je suis également ouvert à d’autres solutions supplémentaires.

Éditez 1 pour le rendre plus clair:

Je veux seulement “voir” les actions de l’utilisateur sur un dossier. Si je manipule des éléments de mon programme ici, je ne veux pas voir ces événements.

Avec mon implémentation, je reçois des événements pour les sous-dossiers si un dossier est verrouillé et ne peut pas être supprimé.

Ce n’est pas si facile d’expliquer en anglais car je ne suis pas un anglophone;).

Edit 2:

5.) Peut-être est-il possible de filtrer dans FileSystemWatcher tous les événements d’un processus défini?

J’ai fait exactement ce genre de chose récemment; L’astuce consiste à ce que votre “liste” reconnaisse qu’il existe un nom de dossier dans la liste, supprime également tout événement de ce dossier s’il attend un événement à supprimer et ne le supprime de votre liste de prédiction que s’il s’agit du dossier lui-même.

Je dois toutefois vous avertir que vous rencontrerez probablement des problèmes lorsque le tampon FileSystemWatcher est FileSystemWatcher si trop d’événements surviennent en succession rapide; Si cela se produit, un événement d’ Error déclenché et les événements ne sont pas signalés. Si votre liste de prédiction supprime les éléments au fur et à mesure qu’elle reçoit l’événement, vous courez le risque d’ignorer les événements futurs simplement parce que l’événement que vous souhaitez ignorer n’a jamais été reçu en raison d’un débordement de mémoire tampon. Il peut également devenir très volumineux, car les éléments ne sont jamais supprimés de la liste.

Je n’ai pas encore trouvé de moyen fiable d’y parvenir, même si vous pouvez définir la taille maximale de la mémoire tampon FileSystemWatcher afin de l’atténuer dans une certaine mesure.

EDIT: également très important: les événements qui reviennent le font sur un autre thread (à moins que votre gestionnaire ne se trouve sur un object qui implémente ISynchronizeInvoke , tel qu’un Control ou un Form , et que vous définissez l’object SynchronizingObject sur votre Control / Form . Vous devez faire très attention à la manière dont vous gérez votre liste, en tenant compte des conditions de course potentielles. Je continue à me débattre avec celle-ci; mon code vide la liste de prédiction lors de la réception d’un événement d’erreur, mais au moment où il gère l’événement, autre changement. les événements depuis l’erreur ont déjà été déclenchés et traités, et il évite les choses qu’il ne devrait pas.

En ce qui concerne le débordement de tampon. La meilleure façon de le résoudre est de faire le travail en réponse à un événement sur un autre thread. Je le fais comme ça

 // Queue of changed paths. private readonly Queue mEventQueue = new Queue(); // 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() { ssortingng 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 } } 

De cette façon, je ne manquerai jamais un événement

Ok voici ma solution du problème:

Juste pour la commande de suppression:

J’ai implémenté 2 listes, une pour les suppressions de fichiers et une pour les suppressions de dossiers.

les entrées de liste de fichiers n’ont pas de délai d’expiration. Si je supprime un fichier, je crée une entrée de liste et si j’obtiens l’événement de suppression attendu, je supprime l’entrée comme auparavant.

les entrées de liste de dossiers n’ont pas de délai d’expiration après la création. Je peux les commander manuellement pour qu’ils dépassent le délai d’une seconde par une méthode spéciale. Si je supprime un dossier, j’ajoute une entrée à la liste deleteFolder. Chaque événement de suppression de ce dossier ou fichier, sous-dossier ou sous-dossier est ignoré à cause de cette entrée de dossier de suppression. Une fois la suppression terminée, j’arme le délai d’attente pour l’entrée deleteFolder. Si la suppression lève une exception, je fais la même chose. Je m’attends donc à avoir tous les événements après une seconde. Donc, j’ignore tous les événements si la commande delete fonctionne ou non. Ensuite, l’entrée de la liste deleteFolder est supprimée.

Limitations: 1. tous les événements de suppression doivent arriver dans la seconde qui suit la suppression. 2. il n’est pas permis de supprimer un dossier comme celui-ci:
supprimer le dossier (terminé)
recréer un dossier
attendre moins d’une seconde
Supprimez à nouveau le dossier (le délai n’a pas été écoulé pour l’entrée de la liste de suppression)

J’espère que cela aide quelqu’un même si c’est très compliqué ^^