67 votes

Comment définir un filtre pour FileSystemWatcher pour plusieurs types de fichiers ?

Partout, je trouve ces deux lignes de code utilisées pour définir le filtre pour l'observateur de système de fichiers dans les échantillons fournis

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Filter = "*.txt";
//or
watcher.Filter = "*.*";

Mais je veux que mon observateur surveille plus de types de fichiers, mais pas tous. Comment puis-je réaliser cela ?

//watcher.Filter = "*.txt" | "*.doc" | "*.docx" | "*.xls" | "*.xlsx";

J'ai essayé ceux-là :

 watcher.Filter = "*.txt|*.doc|*.docx|*.xls|*.xlsx"; 
 // and
 watcher.Filter = "*.txt;*.doc;*.docx;*.xls;*.xlsx*";

Les deux n'ont pas fonctionné. Ce n'est que l'essentiel, mais cela me manque. Merci

85voto

Anders Abel Points 36203

Vous ne pouvez pas faire ça. Le site Filter ne prend en charge qu'un seul filtre à la fois. De la documentation :

Utilisation de filtres multiples tels que *.txt|*.doc n'est pas prise en charge.

Vous devez créer un FileSystemWatcher pour chaque type de fichier. Vous pouvez alors les lier tous au même ensemble de FileSystemEventHandler :

string[] filters = { "*.txt", "*.doc", "*.docx", "*.xls", "*.xlsx" };
List<FileSystemWatcher> watchers = new List<FileSystemWatcher>();

foreach(string f in filters)
{
    FileSystemWatcher w = new FileSystemWatcher();
    w.Filter = f;
    w.Changed += MyChangedHandler;
    watchers.Add(w);
}

1 votes

Ok, merci pour ça. Je n'ai même pas besoin d'attendre d'autres réponses puisque Microsoft me dit en face que ce n'est pas possible ! :x :)

2 votes

D'après la réponse de pbls624, cela est moins inefficace que de s'inscrire à l'université. *.* et faire le filtrage manuellement.

2 votes

Tout ce que j'ai à dire, c'est ....wow. Je suis en admiration. A la fois à cause de l'intelligence derrière ce code et de la faute des gars de Microsoft qui ont exigé quelque chose comme ça ! @AndersAbel, bon travail !

56voto

Mrchief Points 25418

Il existe une solution de contournement.

L'idée est de surveiller toutes les extensions et ensuite, dans l'événement OnChange, de filtrer les extensions souhaitées :

FileSystemWatcher objWatcher = new FileSystemWatcher(); 
objWatcher.Filter = "*.*"; 
objWatcher.Changed += new FileSystemEventHandler(OnChanged); 

private static void OnChanged(object source, FileSystemEventArgs e) 
{ 
    // get the file's extension 
    string strFileExt = getFileExt(e.FullPath); 

    // filter file types 
    if (Regex.IsMatch(strFileExt, @"\.txt)|\.doc", RegexOptions.IgnoreCase)) 
    { 
        Console.WriteLine("watched file type changed."); 
    } 
}

1 votes

Belle solution de contournement. Savez-vous si cela affectera les performances ?

3 votes

Anders Abel : Votre supposition est aussi bonne que la mienne ! Si le dossier surveillé reçoit beaucoup de modifications de fichiers, et si la plupart de ces modifications sont pour non regardé types de fichiers, alors vous encourez une pénalité. Sinon, cela ne devrait pas être une charge trop importante. En fin de compte, il n'y a rien d'autre que vous puissiez faire, n'est-ce pas ? (à moins de passer à l'API Win32)

0 votes

Haha. Mrchief, une solution de contournement cool. Je ne suis pas sûr que je choisirais cette solution. @Anders Abel a donné une autre solution. Maintenant je ne sais plus laquelle marquer comme réponse :)

23voto

pbls624 Points 211

Un rapide coup d'œil dans le réflecteur montre que le filtrage est effectué dans le code .Net après que l'api Windows a signalé le changement de système de fichiers.

Je dirais donc que l'approche consistant à enregistrer plusieurs observateurs est inefficace, car vous chargez davantage l'API en provoquant de multiples rappels et un seul des filtres correspondra. Il est préférable d'enregistrer un seul observateur et de filtrer les résultats vous-même.

21voto

Joe the Coder Points 452

Pour développer la solution de Mrchief et de jdhurst :

private string[] extensions = { ".css", ".less", ".cshtml", ".js" };
private void WatcherOnChanged(object sender, FileSystemEventArgs fileSystemEventArgs)
{
    var ext = (Path.GetExtension(fileSystemEventArgs.FullPath) ?? string.Empty).ToLower();

    if (extensions.Any(ext.Equals))
    {
        // Do your magic here
    }
}

Cela permet d'éliminer le vérificateur de regex (qui, à mon avis, représente une surcharge trop importante) et d'utiliser Linq à notre avantage :)

Modifié - Ajout de la vérification de nullité pour éviter une éventuelle NullReferenceException.

4 votes

Pourquoi ne pas utiliser simplement "extensions.Contains(ext)" ? C'est plus simple. Ou encore mieux, "extensions.Contains(ext, StringComparer.InvariantCultureIgnoreCase)".

14voto

xandermonkey Points 882

Depuis la version .Net Core 3.x et l'aperçu .Net 5, vous pouvez simplement ajouter plusieurs filtres à l'option Filters collection.

var watcher = new FileSystemWatcher();
watcher.Path = "/your/path";
watcher.Filters.Add("*.yml");
watcher.Filters.Add("*.yaml");
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
watcher.EnableRaisingEvents = true;

Sinon, si vous aimez les initialisateurs d'objets,

var watcher = new FileSystemWatcher
    {
        Path = "/your/path",
        Filters = {"*.yml", "*.yaml"},
        NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName,
        EnableRaisingEvents = true,
    };

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X