Je dois configurer une application qui surveille les fichiers en cours de création dans un répertoire, à la fois localement ou sur un lecteur réseau.
La FileSystemWatcher
ou l'interrogation sur une minuterie serait-elle la meilleure option? J'ai utilisé les deux méthodes par le passé, mais pas de manière approfondie.
Quels problèmes (performances, fiabilité, etc.) existe-t-il avec l'une ou l'autre méthode?
J'ai vu l'échec de l'observateur de système de fichiers dans les environnements de production et de test. Je considère maintenant cela comme une commodité, mais je ne le considère pas comme fiable. Mon modèle a été de surveiller les modifications avec l'observateur du système de fichiers, mais interroge de temps en temps pour détecter les modifications de fichiers manquantes.
Modifier: si vous avez une interface utilisateur, vous pouvez également donner à votre utilisateur la possibilité d'actualiser les modifications au lieu de procéder à une interrogation. Je combinerais cela avec un observateur de système de fichiers.
Le plus gros problème que j'ai eu est celui de fichiers manquants lorsque la mémoire tampon est pleine. Facile à résoudre - augmentez simplement le tampon. N'oubliez pas qu'il contient les noms de fichier et les événements, augmentez-le donc jusqu'à la quantité de fichiers attendue (essai et erreur). Il utilise une mémoire qui ne peut pas être extraite, ce qui pourrait forcer d'autres processus à paginer si la mémoire est insuffisante.
Voici l'article de MSDN sur le tampon: FileSystemWatcher .. ::. InternalBufferSize, propriété
Par MSDN:
L'augmentation de la taille de la mémoire tampon est coûteuse, car elle provient d'une mémoire non paginée qui ne peut pas être échangée sur un disque. Aussi, gardez la mémoire tampon aussi petite que possible. Pour éviter un débordement de mémoire tampon, utilisez les propriétés NotifyFilter et IncludeSubdirectories afin de filtrer les notifications de modifications indésirables.
Nous utilisons 16 Mo en raison d’un gros lot attendu en même temps. Fonctionne bien et ne manque jamais un fichier.
Nous lisons également tous les fichiers avant de commencer à en traiter même un ... récupérez les noms de fichiers en toute sécurité (dans notre cas, dans une table de base de données), puis traitez-les.
Pour les problèmes de verrouillage de fichier, je crée un processus qui attend que le fichier soit déverrouillé en attendant une seconde, puis deux, puis quatre, et cetera. Nous jamais sondons. Ceci est en production sans erreur depuis environ deux ans.
La variable FileSystemWatcher
peut également manquer des modifications pendant les heures de pointe, si le nombre de modifications en file d'attente dépasse le tampon fourni. Ce n'est pas une limitation de la classe .NET en soi, mais de l'infrastructure Win32 sous-jacente. Selon notre expérience, le meilleur moyen de minimiser ce problème consiste à retirer de la file d'attente les notifications le plus rapidement possible et à les traiter sur un autre thread.
Comme mentionné par @ChillTemp ci-dessus, l'observateur peut ne pas fonctionner sur des partages autres que Windows. Par exemple, cela ne fonctionnera pas du tout sur les lecteurs Novell montés.
Je conviens qu’un bon compromis est de faire un sondage occasionnel pour recueillir les changements manqués.
Notez également que l'observateur de système de fichiers n'est pas fiable sur les partages de fichiers. En particulier si le partage de fichiers est hébergé sur un serveur autre que Windows. FSW ne doit pas être utilisé pour des tâches critiques. Ou devrait être utilisé avec un sondage occasionnel pour vérifier qu'il n'a rien manqué.
Personnellement, j'ai utilisé la FileSystemWatcher
sur un système de production, et cela a bien fonctionné. Au cours des 6 derniers mois, il n'a pas eu un seul hoquet fonctionnant 24x7. Il surveille un seul dossier local (qui est partagé). Nous avons un nombre relativement réduit d'opérations sur les fichiers qu'il doit gérer (10 événements déclenchés par jour). Ce n'est pas quelque chose qui m'inquiète. Je l'utiliserais encore si je devais refaire la décision.
J'utilise actuellement le FileSystemWatcher
sur un fichier XML mis à jour en moyenne toutes les 100 millisecondes.
J'ai constaté que tant que le FileSystemWatcher
est correctement configuré, vous ne devriez jamais avoir de problèmes avec local files.
Je n'ai aucune expérience en matière de visionnage de fichiers à distance et de partages autres que Windows.
Je considérerais que l'interrogation du fichier est redondante et ne vaut pas la charge, sauf si vous vous méfiez intrinsèquement de FileSystemWatcher
ou si vous avez directement expérimenté les limitations que tout le monde a énumérées (partages autres que Windows et surveillance de fichiers à distance).
J'ai eu du mal à utiliser FileSystemWatcher
sur des partages réseau. Si vous êtes dans un environnement Windows pur, ce n'est peut-être pas un problème, mais je surveillais un partage NFS et, puisque NFS est sans état, il n'y a jamais eu de notification de modification du fichier que je surveillais.
J'irais avec les sondages.
Des problèmes de réseau rendent la FileSystemWatcher
non fiable (même en cas de surcharge de l'événement d'erreur).
J'ai eu de gros problèmes avec FSW sur les lecteurs réseau: La suppression d'un fichier renvoyait toujours l'événement d'erreur, jamais l'événement supprimé. Je n’ai pas trouvé de solution, j’évite donc le FSW et utilise le polling.
En revanche, les événements de création ont bien fonctionné. Si vous ne devez surveiller que la création de fichier, vous pouvez opter pour le fichier FSW.
De plus, je n’avais aucun problème avec les dossiers locaux, qu’ils soient partagés ou non.
Utiliser à la fois FSW et polling est une perte de temps et de ressources, à mon avis, et je suis surpris que des développeurs expérimentés le suggèrent. Si vous devez utiliser polling pour rechercher des "erreurs manquées", vous pouvez naturellement vous débarrasser de FSW et utiliser uniquement la scrutation.
J'essaie actuellement de décider si j'utiliserai FSW ou polling pour un projet que je développe. En lisant les réponses, il est évident qu’il existe des cas où FSW répond parfaitement aux besoins, alors que d’autres fois, vous avez besoin de interrogation. Malheureusement, no answer a en fait traité la différence performance (le cas échéant), mais uniquement avec les problèmes de "fiabilité". Quelqu'un peut-il répondre à cette partie de la question?
Le point de EDIT: nmclean pour la validité de l'utilisation simultanée de FSW et de polling (vous pouvez lire la discussion dans les commentaires, si cela vous intéresse) semble bien expliquer pourquoi FSW et polling est efficace. Merci de m'avoir éclairé à ce sujet pour moi (et pour tous ceux qui ont le même avis), nmclean.
Solution pratique pour travailler avec create event au lieu de changer
Même pour copier, couper, coller, déplacer.
class Program
{
static void Main(string[] args)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
FileSystemWatcher.Path = SourceFolderPath;
FileSystemWatcher.IncludeSubdirectories = false;
FileSystemWatcher.NotifyFilter = NotifyFilters.FileName; // ON FILE NAME FILTER
FileSystemWatcher.Filter = "*.txt";
FileSystemWatcher.Created +=FileSystemWatcher_Created; // TRIGGERED ONLY FOR FILE GOT CREATED BY COPY, CUT PASTE, MOVE
FileSystemWatcher.EnableRaisingEvents = true;
Console.Read();
}
static void FileSystemWatcher_Created(object sender, FileSystemEventArgs e)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
try
{
// DO SOMETING LIKE MOVE, COPY, ETC
File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
}
catch
{
}
}
}
Solution pour cet observateur de fichier en cas de changement d'attribut de fichier à l'aide du stockage statique
class Program
{
static string IsSameFile = string.Empty; // USE STATIC FOR TRACKING
static void Main(string[] args)
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
FileSystemWatcher FileSystemWatcher = new FileSystemWatcher();
FileSystemWatcher.Path = SourceFolderPath;
FileSystemWatcher.IncludeSubdirectories = false;
FileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
FileSystemWatcher.Filter = "*.txt";
FileSystemWatcher.Changed += FileSystemWatcher_Changed;
FileSystemWatcher.EnableRaisingEvents = true;
Console.Read();
}
static void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
if (e.Name == IsSameFile) //SKIPS ON MULTIPLE TRIGGERS
{
return;
}
else
{
string SourceFolderPath = "D:\\SourcePath";
string DestinationFolderPath = "D:\\DestinationPath";
try
{
// DO SOMETING LIKE MOVE, COPY, ETC
File.Copy(e.FullPath, DestinationFolderPath + @"\" + e.Name);
}
catch
{
}
}
IsSameFile = e.Name;
}
}
Ceci est une solution de contournement pour ce problème d'événement déclencheur multiple.
Je dirais que vous devez utiliser polling, en particulier dans un scénario TDD, car il est beaucoup plus facile de simuler/stub la présence de fichiers ou autrement lorsque l'événement polling est déclenché que de compter sur l'événement fsw plus "non contrôlé". + à celui ayant travaillé sur un certain nombre d'applications qui étaient en proie à des erreurs fsw.
Revenir de la méthode d'événement le plus rapidement possible, en utilisant un autre thread, a résolu le problème pour moi:
private void Watcher_Created(object sender, FileSystemEventArgs e)
{
Task.Run(() => MySubmit(e.FullPath));
}