如何为多种文件类型设置FileSystemWatcher的过滤器?

naw*_*fal 61 .net c# filesystemwatcher

无处不在,我发现这两行代码用于为提供的样本中的文件系统观察器设置过滤器.

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Filter = "*.txt";
//or
watcher.Filter = "*.*";
Run Code Online (Sandbox Code Playgroud)

但我希望我的观察者能够监控更多的文件类型,但不是全部.我怎样才能做到这一点:

//watcher.Filter = "*.txt" | "*.doc" | "*.docx" | "*.xls" | "*.xlsx";
Run Code Online (Sandbox Code Playgroud)

我试过这些:

 watcher.Filter = "*.txt|*.doc|*.docx|*.xls|*.xlsx"; 
 // and
 watcher.Filter = "*.txt;*.doc;*.docx;*.xls;*.xlsx*";
Run Code Online (Sandbox Code Playgroud)

两者都没用.这只是基础,但我想念它.谢谢..

And*_*bel 80

你不能这样做.该Filter属性一次只支持一个过滤器.从文档:

*.txt|*.doc不支持使用多个过滤器.

您需要FileSystemWatcher为每种文件类型创建一个.然后,您可以将它们全部绑定到同一组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);
}
Run Code Online (Sandbox Code Playgroud)

  • 根据pbls624的回答,这比注册`*.*`效率低,并且手动进行过滤. (2认同)
  • 我要说的是......哇。我很敬畏。既是因为这段代码背后的才华,也是因为微软需要这样的东西的人的过错!@AndersAbel,干得好! (2认同)

Mrc*_*ief 52

有一个解决方法.

我们的想法是观察所有扩展,然后在OnChange事件中过滤掉所需的扩展:

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."); 
    } 
} 
Run Code Online (Sandbox Code Playgroud)

  • @Anders Abel:你的猜测和我一样好!如果监视文件夹的文件更改很多,并且大多数更改都是针对_unwatched_文件类型的,那么您将受到惩罚.否则,它不应该是一个很大的开销.最后,你无能为力,对吗?(除非转到Win32 API) (3认同)
  • @nawfal:不,我不确定 - 确定需要做一些分析.我猜我的方法会更好,如果有很少的类型要观看,许多文件与模式不匹配.MrChief的方法在相反的情况下效果最好:大多数文件匹配并且有许多模式.为了代码可读性,我更喜欢我的 - 它提供了更清晰的事件处理程序. (3认同)
  • 请注意,设置观察者也需要相当多的资源。如果您期望有很多文件(否则性能无论如何都不会成为问题),您需要将观察者的缓冲区大小设置为高于默认值的数字,因此您将分配相当多的内存(与 CPU 相反) Mrchief的解决方案) (2认同)
  • 比 RegEx 简单得多的是只需查找 `if (strFileExt.ToLower().EndsWith(".txt") || strFileExt.ToLower().EndsWith(".doc")) { ... }` (2认同)

Joe*_*der 17

扩展Mrchief和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
    }
}
Run Code Online (Sandbox Code Playgroud)

这消除了正则表达式检查程序(在我看来是太多的开销),并利用Linq我们的优势.:)

已编辑 - 添加了空检查以避免可能的NullReferenceException.

  • 为什么不只使用"extensions.Contains(ext)"?简单.甚至更好,"extensions.Contains(ext,StringComparer.InvariantCultureIgnoreCase)" (3认同)

小智 17

快速查看反射器显示,在windows api报告文件系统更改后,过滤在.Net代码中完成.

因此,我建议注册多个观察者的方法是低效的,因为你在API上施加更多负载导致多个回调,并且只有一个过滤器匹配.最好只注册一个观察者并自己过滤结果.


xan*_*key 12

从 .Net Core 3.x 和 .Net 5 Preview 开始,您可以简单地向Filters集合中添加多个过滤器。

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;
Run Code Online (Sandbox Code Playgroud)

或者,如果您喜欢对象初始值设定项,

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

Run Code Online (Sandbox Code Playgroud)