using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace JiShe.CollectBus.PluginFileWatcher
{
///
/// 文件监控相关工具类
///
public static class FileWatcherUtils
{
///
/// 检测文件是否被锁定
///
/// 要检查的文件路径
/// 如果文件被锁定则返回true,否则返回false
public static bool IsFileLocked(string filePath)
{
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
return false;
try
{
using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
// 文件可以被完全访问,没有被锁定
stream.Close();
}
return false;
}
catch (IOException)
{
// 文件被锁定或正在被其他进程使用
return true;
}
catch (Exception)
{
// 其他错误(权限不足、路径无效等)
return true;
}
}
///
/// 尝试处理一个可能被锁定的文件
///
/// 文件路径
/// 成功解锁后要执行的操作
/// 健壮性配置
/// 处理结果:true表示成功处理,false表示处理失败
public static async Task TryHandleLockedFileAsync(string filePath, Func action, RobustnessConfig config)
{
if (!config.EnableFileLockDetection)
{
// 如果禁用了锁检测,直接执行操作
try
{
await action();
return true;
}
catch
{
return false;
}
}
// 如果文件不存在或不是锁定状态,直接执行操作
if (!File.Exists(filePath) || !IsFileLocked(filePath))
{
try
{
await action();
return true;
}
catch
{
return false;
}
}
// 文件被锁定,根据策略处理
switch (config.LockedFileStrategy.ToLower())
{
case "skip":
// 跳过这个文件
Console.WriteLine($"文件被锁定,已跳过: {filePath}");
return false;
case "retry":
// 重试几次
for (int i = 0; i < config.FileLockRetryCount; i++)
{
await Task.Delay(config.FileLockRetryDelayMs);
if (!IsFileLocked(filePath))
{
try
{
await action();
Console.WriteLine($"文件锁已释放,成功处理: {filePath}");
return true;
}
catch
{
// 继续重试
}
}
}
Console.WriteLine($"文件仍然被锁定,重试{config.FileLockRetryCount}次后放弃: {filePath}");
return false;
case "log":
default:
// 只记录不处理
Console.WriteLine($"文件被锁定,已记录: {filePath}");
return false;
}
}
///
/// 检查文件系统监控器是否健康
///
/// 要检查的监控器
/// 最后一次事件的时间
/// 健壮性配置
/// 如果监控器健康则返回true,否则返回false
public static bool IsWatcherHealthy(FileSystemWatcher watcher, DateTime lastEventTime, RobustnessConfig config)
{
if (watcher == null || !watcher.EnableRaisingEvents)
return false;
// 如果配置了超时时间,检查是否超时
if (config.WatcherTimeoutSeconds > 0)
{
// 如果最后事件时间超过了超时时间,认为监控器可能已经失效
TimeSpan timeSinceLastEvent = DateTime.UtcNow - lastEventTime;
if (timeSinceLastEvent.TotalSeconds > config.WatcherTimeoutSeconds)
{
// 执行一个简单的测试:尝试改变一些属性看是否抛出异常
try
{
var currentFilter = watcher.Filter;
watcher.Filter = currentFilter;
return true; // 如果没有异常,认为监控器仍然正常
}
catch
{
return false; // 抛出异常,认为监控器已经失效
}
}
}
// 默认情况下认为监控器健康
return true;
}
}
}