当前位置: 首页 > news >正文

[ IO.File ] FileSystemWatcher

    示例:

private FileSystemWatcher watcher = null;
private int _countFileChangeEvent = 0;
private static log4net.ILog log = log4net.LogManager.GetLogger(typeof(Form1));

private void Form1_Load(object sender, EventArgs e)
{
    watcher 
= new FileSystemWatcher();
    watcher.Path 
= "c:\\t"// System.AppDomain.CurrentDomain.BaseDirectory;
    watcher.IncludeSubdirectories = false;
    watcher.Filter 
= "*.xml"//"*.*"; "log4net.config";
    watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.FileName;

    watcher.Changed 
+= new FileSystemEventHandler(FileChanged_Handler);
    watcher.Created 
+= new FileSystemEventHandler(FileChanged_Handler);
    watcher.Deleted 
+= new FileSystemEventHandler(FileChanged_Handler);
    watcher.Renamed 
+= new RenamedEventHandler(FileRenamed_Handler);

    watcher.EnableRaisingEvents 
= true;
}


private void FileChanged_Handler(object source, FileSystemEventArgs e)
{
    _countFileChangeEvent
++;
    log.InfoFormat(
"FileEvent {0} : {1} - {2}"
        _countFileChangeEvent.ToString(
"#00"), 
        e.ChangeType, 
        e.FullPath);
}


private void FileRenamed_Handler(object source, RenamedEventArgs e)
{
    _countFileChangeEvent
++;
    log.InfoFormat(
"FileEvent {0} : {1} - Old Path : {2} New Path : {3}"
        _countFileChangeEvent.ToString(
"#00"), 
        e.ChangeType, 
        e.OldFullPath, 
        e.FullPath);
}
    1. BufferSize
    Windows操作系统使用FileSystemWatcher创建的一个内存缓冲区通知程序文件的修改信息,如果在很短的时间内有非常多的文件修改,这个缓冲区会溢出, 造成部分追踪丢失,并且FileSystemWatcher不会产生异常。加大InternalBufferSize属性值可以避免这种情况。
    InternalBufferSize默认值是8K,可以设置的最小值是4K,增加或减小InternalBufferSize最好用4K的整数倍。每一个事件通知需要使用16字节,并不包含文件名。InternalBufferSize的内存来自non-paged内存,注意这部分内存资源比较宝贵。
    使用NotifyFilter、IncludeSubdirectories属性减小trace范围,设置filter属性并不会影响进入缓冲区的事件通知,另外尽快的完成事件处理,也是避免缓冲区溢出造成事件丢失的一个措施。
    2. 隐藏文件也会监控
    3. 有些系统中,FileSystemWatcher的事件里对长文件名使用8.3短文件名方式表示。
    4. 如果多个FileSystemWatcher在监控同一个对象,在Windows XP在没有打SP1之前,Windows 2000 SP2或之前的操作系统中,只会有一个FileSystemWatcher接收到通知;更新版本的操作系统中所有FileSystemWatcher都会收到通知。
    5. 一次文件操作产生多个事件通知
    某些文件操作可能会引发多个文件更改事件,例如新增文件、拷贝粘贴一个新的文件等。上面的示例代码使用log4net记录日志,用一个计数器记录事件编号,当Copy一个xml文件并粘贴到c:\t目录下时,从日志文件中可以看到会产生多个事件:一个Created和多个Changed。微软的解释是文件系统的操作比较复杂,另外还有其它程序的影响(例如杀毒软件等)。
    初步测试,Rename、Delete、New只会触发一个事件,Save、Paste时会有多个事件。
    在某些项目中经常需要监控某个配置文件的修改,实时加载配置信息到程序中,这种情况下可以参考log4net的做法。通过一个计时器,在文件事件处理中让计时器延迟一段时间之后,再执行加载新的配置文件操作。这样可以避免对文件做一次操作触发了多个更改事件,而多次加载配置文件。示例如下:

private FileSystemWatcher watcher = null;
private int _countFileChangeEvent = 0, _countTimerEvent = 0;
private System.Threading.Timer m_timer;
private const int TimeoutMillis = 500;
private static log4net.ILog log = log4net.LogManager.GetLogger(typeof(Form1));

private void Form1_Load(object sender, EventArgs e)
{
    watcher 
= new FileSystemWatcher();
    watcher.Path 
= "c:\\t"// System.AppDomain.CurrentDomain.BaseDirectory;
    watcher.IncludeSubdirectories = false;
    watcher.Filter 
= "*.xml"//"*.*"; "log4net.config";
    watcher.NotifyFilter = NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.FileName;

    watcher.Changed 
+= new FileSystemEventHandler(FileChanged_Handler);
    watcher.Created 
+= new FileSystemEventHandler(FileChanged_Handler);
    watcher.Deleted 
+= new FileSystemEventHandler(FileChanged_Handler);
    watcher.Renamed 
+= new RenamedEventHandler(FileRenamed_Handler);

    watcher.EnableRaisingEvents 
= true;

    m_timer 
= new System.Threading.Timer(
        
new System.Threading.TimerCallback(FileChanged_TimerChanged), 
        
null
        System.Threading.Timeout.Infinite, 
        System.Threading.Timeout.Infinite);
}


private void FileChanged_Handler(object source, FileSystemEventArgs e)
{
    _countFileChangeEvent
++;
    log.InfoFormat(
"FileEvent {0} : {1} - {2}"
        _countFileChangeEvent.ToString(
"#00"), e.ChangeType, e.FullPath);
    m_timer.Change(TimeoutMillis, System.Threading.Timeout.Infinite);
}


private void FileRenamed_Handler(object source, RenamedEventArgs e)
{
    _countFileChangeEvent
++;
    log.InfoFormat(
"FileEvent {0} : {1} - Old Path : {2} New Path : {3}"
        _countFileChangeEvent.ToString(
"#00"), e.ChangeType, e.OldFullPath, e.FullPath);
    m_timer.Change(TimeoutMillis, System.Threading.Timeout.Infinite);
}


private void FileChanged_TimerChanged(object state)
{
    
this.FileChanged();
}


private void FileChanged()
{
    _countTimerEvent
++;
    log.InfoFormat(
"TimerEvent {0}",_countTimerEvent.ToString("#00"));
}
    上面例子用log4net分别记录了FileSystemWatcher事件和Timer的Change事件,这样可以做一个简单的分析。
    操作如下:对一个文件重命名,拷贝粘贴一个文件,打开一个文件进行修改后保存,选择2个文件删除,记录的log如下:
2006-12-16 22:50:07,828 [2904] - FileEvent 01 : Renamed - Old Path : c:\t\a.xml New Path : c:\t\b.xml
2006-12-16 22:50:08,359 [3828] - TimerEvent 01
2006-12-16 22:50:49,171 [2904] - FileEvent 02 : Created - c:\t\Copy of b.xml
2006-12-16 22:50:49,171 [2904] - FileEvent 03 : Changed - c:\t\Copy of b.xml
2006-12-16 22:50:49,171 [2904] - FileEvent 04 : Changed - c:\t\Copy of b.xml
2006-12-16 22:50:49,671 [3828] - TimerEvent 02
2006-12-16 22:51:02,312 [2904] - FileEvent 05 : Changed - c:\t\1.xml
2006-12-16 22:51:02,312 [2904] - FileEvent 06 : Changed - c:\t\1.xml
2006-12-16 22:51:02,812 [3828] - TimerEvent 03
2006-12-16 22:51:15,250 [2904] - FileEvent 07 : Deleted - c:\t\1.xml
2006-12-16 22:51:15,250 [2904] - FileEvent 08 : Deleted - c:\t\Copy of b.xml
2006-12-16 22:51:15,750 [3828] - TimerEvent 04
    可以看到,一个文件操作引起多个文件更改事件时,Timer的Change事件都只执行了一次。
    6. 有人想同时监控多种类型的文件,例如*.xml + *.config,发现Filter属性不支持这种设置(只能够设置一种)。
    这种情况下可以将Filter属性设成*.*,在事件里用if (e.FullPath.EndsWith(".xml") || e.FullPath.EndsWith(".config"))自己判断过滤一下。记得Filter属性的设置并不会减少进入缓冲区的事件通知,因此上面的方法并不会带来多少性能损失。

相关文章:

  • T-SQL遗漏值NULL
  • 通过COM来获取CookieContainer,简单又好用
  • 一个实例来简单的说明接口
  • ASP.NET 2.0 Web Part编程之定制Web Part
  • .NET 指南:抽象化实现的基类
  • 浮动静态路由
  • 范伟导老师Sniffer课程资料
  • 春节期间新闻回顾:思科微软多事 熊猫烧香完事
  • Windows Mobile 6 SDK 正式发布!
  • 怎样用javascript操作ftb编辑区内容
  • 局域网防雷电***实用解决方案
  • 系统不显示桌面的原因和解决方法
  • 让Windows下的驱动乖乖在Linux中安家!
  • Linux下文件和目录的颜色代表的含义
  • 哈哈,毒霸可以直接关闭自动播放功能,真是太棒了
  • $translatePartialLoader加载失败及解决方式
  • 〔开发系列〕一次关于小程序开发的深度总结
  • 08.Android之View事件问题
  • 10个确保微服务与容器安全的最佳实践
  • ES6简单总结(搭配简单的讲解和小案例)
  • gops —— Go 程序诊断分析工具
  • Sass 快速入门教程
  • SpriteKit 技巧之添加背景图片
  • Vue小说阅读器(仿追书神器)
  • 分布式事物理论与实践
  • 开发基于以太坊智能合约的DApp
  • 每天10道Java面试题,跟我走,offer有!
  • 扑朔迷离的属性和特性【彻底弄清】
  • 双管齐下,VMware的容器新战略
  • 小程序 setData 学问多
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #define用法
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • %@ page import=%的用法
  • ( 10 )MySQL中的外键
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (pojstep1.1.2)2654(直叙式模拟)
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (zhuan) 一些RL的文献(及笔记)
  • (二)构建dubbo分布式平台-平台功能导图
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (算法二)滑动窗口
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (转) 深度模型优化性能 调参
  • (转)Sql Server 保留几位小数的两种做法
  • (转载)hibernate缓存
  • *1 计算机基础和操作系统基础及几大协议
  • ./configure、make、make install 命令
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .Net Core webapi RestFul 统一接口数据返回格式
  • .net core webapi 大文件上传到wwwroot文件夹