System.IO.FileSystemWatcher 监视目录文件的状态

本文介绍了如何使用System.IO.FileSystemWatcher类来监视目录文件的状态,包括文件的创建、删除和更改事件。通过设置Filter可以指定监控特定类型的文件,而NotifyFilter则用于选择要监视的文件属性变化。需要注意的是,启用EnableRaisingEvents属性才能使事件生效。

System.IO.FileSystemWatcher

MSDN 说明:侦听文件系统更改通知,并在目录或目录中的文件发生更改时引发事件。 

这两天看到论坛上关于如何监视目录文件的状态帖子很多,自己今天也在看System.IO下面的类,就顺便把他给看了,并实验了一下,其实此类用起来非常简单,不过有两三个地方需要注意下,下面把需要注意的地方说一下

  System.IO.FileSystemWatcher watch = new FileSystemWatcher("D://1//");       //初始化目录监视
            watch.Filter = "*.txt";                      //监视的对象,目录中监视哪些文件,默认为*.*
           //不过这里有个好玩的地方,实验证明,通配符可以用在很多地方,比如可以设置成为  watch.Filter = "*.tx*";    针对具体文件就写具体文件名
            watch.Changed += new FileSystemEventHandler(watch_Changed);         //文件改变事件
           

public class CustomerWatcher { System.IO.FileSystemWatcher watcher = new System.IO.FileSystemWatcher(); List<string> currentpathList= new List<string>(); public void Watch(string Path) { watcher.Path = Path; watcher.NotifyFilter = System.IO.NotifyFilters.LastAccess | System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName; watcher.Changed += new System.IO.FileSystemEventHandler(OnChanged); watcher.Created += new System.IO.FileSystemEventHandler(OnCreated); watcher.Deleted += new System.IO.FileSystemEventHandler(OnChanged); watcher.Renamed += new System.IO.RenamedEventHandler(OnRenamed); watcher.EnableRaisingEvents = true; } private void OnChanged(object source, System.IO.FileSystemEventArgs e) { Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType); string filePath = e.FullPath; List<string> filePathList = filePath.Split("\\").ToList(); int filePathListCount = filePathList.Count(); if (filePathListCount < 6) { return; } else if (filePathListCount > 6) { for(int i= filePathListCount - 1;i>=6;i--) { filePathList.RemoveAt(i); } } string productRootPath = string.Join("\\", filePathList); if(currentpathList.Contains(productRootPath)) { return; } int delayTime = 300; Thread.Sleep(delayTime); string cust_code=filePathList[2]; string cusr_code_short = cust_code.Split('(')[0]; if(cusr_code_short=="AZ") { } currentpathList.Add(productRootPath); }修改代码,中间这部分代码放到新的线程里面运行,不要阻塞主线程
03-20
<think>好的,我现在需要帮用户修改他们的C#代码,把中间的部分放到新线程里运行,避免阻塞主线程。首先,我需要仔细看一下用户提供的代码,了解他们的需求。 用户有一个CustomerWatcher类,里面有一个OnChanged方法。这个方法现在是在文件系统监视器的事件处理程序中直接执行的,当文件变化时会被触发。问题在于OnChanged中的处理逻辑可能会比较耗时,特别是Thread.Sleep(300)这部分,会导致主线程阻塞,影响整个应用程序的响应速度。用户希望将这部分代码移到新线程中,避免这个问题。 首先,我需要确定哪些代码需要移到新线程里。查看OnChanged方法,从Console.WriteLine开始,一直到currentpathList.Add(productRootPath)这部分,都是处理逻辑。特别是中间的路径处理、休眠、客户代码提取等操作,这些都应该放在后台线程执行,主线程只负责触发事件。 接下来,我需要考虑如何在C#中创建新线程来执行这部分代码。传统的方法是使用Thread类,创建新线程并启动。但是,直接创建新线程可能会带来资源管理的开销,尤其是在频繁触发事件的情况下。另一个选择是使用线程池,通过Task.Run来异步执行,这样可以利用线程池中的线程,更高效地管理资源。 另外,需要注意线程安全问题。因为currentpathList是一个List<string>,多个线程同时操作可能会导致竞争条件。因此,在修改currentpathList时,需要确保线程安全,可以使用锁(lock)来保护这个共享资源。 然后,我需要重构OnChanged方法,将需要在新线程中执行的代码提取出来,封装成一个单独的方法,比如HandleFileChangeAsync。然后,在OnChanged事件处理程序中,调用Task.Run(() => HandleFileChangeAsync(e))来异步执行。 还需要检查是否有其他共享资源需要保护,比如cust_code和cusr_code_short的处理,这些变量如果只在方法内部使用,可能不需要锁,但如果有共享状态,可能需要同步处理。 另外,需要考虑异常处理。在异步执行中,异常不会直接抛到主线程,所以需要在HandleFileChangeAsync方法内部进行适当的异常处理,比如使用try-catch块记录错误,避免应用程序崩溃。 最后,测试修改后的代码,确保文件系统事件的处理不会阻塞主线程,同时保证currentpathList的操作是线程安全的。可能还需要调整线程休眠的时间,或者考虑其他异步等待的方式,比如Task.Delay,但根据用户代码中的Thread.Sleep(300),可能需要保持原来的延迟逻辑,只需将其移到新线程中即可。 总结步骤: 1. 将OnChanged中的处理逻辑提取到单独的方法。 2. 使用Task.Run在新线程中执行该方法。 3. 使用lock关键字保护对currentpathList的访问。 4. 添加异常处理确保稳定性。 5. 测试修改后的代码,确保功能正常且主线程不被阻塞。</think>以下是修改后的代码实现,使用多线程处理文件变更逻辑,避免阻塞主线程: ```csharp public class CustomerWatcher { private readonly System.IO.FileSystemWatcher watcher = new(); private readonly List<string> currentpathList = new(); private readonly object listLock = new(); // 添加线程同步锁 public void Watch(string path) { watcher.Path = path; watcher.NotifyFilter = System.IO.NotifyFilters.LastAccess | System.IO.NotifyFilters.LastWrite | System.IO.NotifyFilters.FileName | System.IO.NotifyFilters.DirectoryName; // 简化的事件注册方式 watcher.Changed += OnChanged; watcher.Created += OnCreated; watcher.Deleted += OnChanged; watcher.Renamed += OnRenamed; watcher.EnableRaisingEvents = true; } private void OnChanged(object source, System.IO.FileSystemEventArgs e) { // 主线程仅触发异步任务 Task.Run(() => HandleFileChangeAsync(e)); } // 新增异步处理方法 private async Task HandleFileChangeAsync(System.IO.FileSystemEventArgs e) { Console.WriteLine($"File: {e.FullPath} {e.ChangeType}"); var filePathList = e.FullPath.Split('\\').ToList(); if (filePathList.Count < 6) return; // 路径处理逻辑 if (filePathList.Count > 6) { filePathList = filePathList.Take(6).ToList(); } string productRootPath = string.Join("\\", filePathList); // 线程安全的集合检查 lock (listLock) { if (currentpathList.Contains(productRootPath)) return; } await Task.Delay(300); // 替换Thread.Sleep为异步等待 // 客户代码处理 var cust_code = filePathList[2]; var cust_code_short = cust_code.Split('(')[0]; if (cust_code_short == "AZ") { // 业务逻辑 } // 线程安全的集合操作 lock (listLock) { currentpathList.Add(productRootPath); } } // 其他事件处理方法... } ``` 主要修改点说明: 1. **异步处理架构**: - 使用 `Task.Run` 将同步方法转为异步操作 - 将原 `OnChanged` 拆分为事件触发和方法逻辑两部分 - 用 `async Task` 声明异步处理方法 2. **线程安全措施**: ```csharp private readonly object listLock = new(); // 同步锁对象 lock (listLock) // 操作共享资源时加锁 { // 操作 currentpathList } ``` 3. **异步延迟替代方案**: ```csharp // 原阻塞式等待 Thread.Sleep(300); // 改为非阻塞式异步等待 await Task.Delay(300); ``` 4. **代码优化细节**: - 使用 `var` 简化变量声明 - 字符串插值替代字符串拼接 - 使用 LINQ 的 `Take()` 方法简化列表截断 - 简化事件注册语法 5. **扩展建议**: - 添加异常处理: ```csharp try { // 业务逻辑 } catch (Exception ex) { Console.WriteLine($"Error processing {e.FullPath}: {ex.Message}"); } ``` - 增加资源释放: ```csharp public void Stop() { watcher.Dispose(); } ``` 修改后的代码通过: 1. 将耗时操作移出主线程 2. 使用异步/await模式 3. 确保线程安全 4. 保持原有业务逻辑 实现了非阻塞的文件监控功能,同时保证了程序的稳定性和执行效率。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值