优势
- 异步处理:提高了文件变化处理的效率,避免了阻塞主线程。
- 线程安全:使用了线程安全的队列来避免多线程环境下的竞态条件。
- 日志记录:异步日志记录减少了对主线程的干扰,并且能够处理大量事件。
- 灵活配置:可以通过配置文件调整监控目录和过滤规则,增加了灵活性。
- 支持子目录:可以监控指定目录及其所有子目录中的文件变化。
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
// 定义一个类来封装文件变化的事件信息
public class FileChangeEvent
{
public string FilePath { get; set; }
public WatcherChangeTypes ChangeType { get; set; }
public DateTime ChangeTime { get; set; }
}
class Program
{
private static FileSystemWatcher _fileSystemWatcher; // 用于监控文件系统的对象
private static ConcurrentQueue<FileChangeEvent> _changeQueue = new ConcurrentQueue<FileChangeEvent>(); // 线程安全的队列,用于存储文件变化事件
private static CancellationTokenSource _cts = new CancellationTokenSource(); // 用于取消异步任务的令牌源
private static string _logFilePath = "file_changes.log"; // 记录日志的文件路径
static async Task Main(string[] args)
{
// 从配置文件读取监控目录和过滤规则
string directoryToWatch = GetConfigValue("DirectoryToWatch", @"C:\Path\To\Directory");
string filter = GetConfigValue("Filter", "*.*");
// 创建FileSystemWatcher实例并配置
_fileSystemWatcher = new FileSystemWatcher(directoryToWatch)
{
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,
Filter = filter,
IncludeSubdirectories = true
};
// 订阅事件
_fileSystemWatcher.Created += OnChanged;
_fileSystemWatcher.Changed += OnChanged;
_fileSystemWatcher.Deleted += OnChanged;
_fileSystemWatcher.Renamed += OnRenamed;
// 开始监视
_fileSystemWatcher.EnableRaisingEvents = true;
// 启动异步任务来处理文件变化事件
Task processingTask = Task.Run(() => ProcessFileChanges(_cts.Token));
Console.WriteLine($"Monitoring changes to: {directoryToWatch}");
Console.WriteLine("Press 'q' to quit the sample.");
// 等待用户输入以结束程序
while (Console.Read() != 'q') ;
// 取消处理任务并等待完成
_cts.Cancel();
await processingTask;
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
// 将文件变化事件添加到队列
_changeQueue.Enqueue(new FileChangeEvent
{
FilePath = e.FullPath,
ChangeType = e.ChangeType,
ChangeTime = DateTime.Now
});
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
// 将重命名事件添加到队列
_changeQueue.Enqueue(new FileChangeEvent
{
FilePath = e.FullPath,
ChangeType = WatcherChangeTypes.Renamed,
ChangeTime = DateTime.Now
});
}
private static async Task ProcessFileChanges(CancellationToken token)
{
// 持续处理队列中的文件变化事件
while (!token.IsCancellationRequested)
{
if (_changeQueue.TryDequeue(out FileChangeEvent changeEvent))
{
// 处理并记录文件变化事件到日志
await LogChangeEventAsync(changeEvent);
}
else
{
// 如果队列为空,稍作等待以减少CPU使用率
await Task.Delay(100, token);
}
}
}
private static async Task LogChangeEventAsync(FileChangeEvent changeEvent)
{
// 异步记录文件变化事件到日志文件
string logMessage = $"{changeEvent.ChangeTime}: {changeEvent.FilePath} - {changeEvent.ChangeType}";
await File.AppendAllTextAsync(_logFilePath, logMessage + Environment.NewLine);
}
private static string GetConfigValue(string key, string defaultValue)
{
// 从配置文件或环境变量读取配置值
// 这里简单地返回默认值,实际应用中可以读取真实的配置
return defaultValue;
}
}