157 lines
5.6 KiB
C#
157 lines
5.6 KiB
C#
|
|
using System;
|
|||
|
|
using System.IO;
|
|||
|
|
using System.Threading;
|
|||
|
|
using System.Threading.Tasks;
|
|||
|
|
|
|||
|
|
namespace JiShe.CollectBus.PluginFileWatcher
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 文件监控相关工具类
|
|||
|
|
/// </summary>
|
|||
|
|
public static class FileWatcherUtils
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 检测文件是否被锁定
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="filePath">要检查的文件路径</param>
|
|||
|
|
/// <returns>如果文件被锁定则返回true,否则返回false</returns>
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 尝试处理一个可能被锁定的文件
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="filePath">文件路径</param>
|
|||
|
|
/// <param name="action">成功解锁后要执行的操作</param>
|
|||
|
|
/// <param name="config">健壮性配置</param>
|
|||
|
|
/// <returns>处理结果:true表示成功处理,false表示处理失败</returns>
|
|||
|
|
public static async Task<bool> TryHandleLockedFileAsync(string filePath, Func<Task> 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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 检查文件系统监控器是否健康
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="watcher">要检查的监控器</param>
|
|||
|
|
/// <param name="lastEventTime">最后一次事件的时间</param>
|
|||
|
|
/// <param name="config">健壮性配置</param>
|
|||
|
|
/// <returns>如果监控器健康则返回true,否则返回false</returns>
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|