using AdService.Controller.Dto;
using Newtonsoft.Json;
namespace AdService.Service
{
///
/// 数据清理服务(每隔5分钟扫描一次)
///
public class CearDirService : BackgroundService
{
ILogger logger { get; set; }
///
/// 数据清理服务
///
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
await Task.Delay(5000, stoppingToken);//延迟一会儿让webbapi先启动
await Task.Run(async () =>
{
#region 读取清理目录配置信息
StreamReader sr = new StreamReader(Directory.GetCurrentDirectory() + "appsettings.json");
string json = sr.ReadToEnd();
// 解析 JSON 字符串
var adConfig = JsonConvert.DeserializeObject(json);
string dataClearStr = adConfig.ClearDir;
var dataClears = dataClearStr.Split(new string[] { ";", ";" }, StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.ToLower()).ToList();
if (!dataClears.Contains(adConfig.DataDir))
dataClears.Add(adConfig.DataDir);
#endregion
#region 检测有效的清理目录并读取清理条件
List list = new List();
foreach (var item in dataClears)
{
var root = Path.GetPathRoot(item);
DriveInfo drive = new DriveInfo(root);
if (!drive.IsReady)
{
continue;
}
if (Directory.Exists(item))
{
list.Add(item);
}
}
if (!list.Any())
{
logger.LogWarning($"配置文件中的数据清理目录无效");
return;
}
float maxPercent = adConfig.ClearCondition;
var clearHours = adConfig.ClearHours;
if (clearHours < 1)
{
clearHours = 1;
}
logger.LogInformation($"已启动目录[{string.Join(";", list)}]自动清理,清理条件=可用空间不足{(int)(maxPercent * 100)}%");
#endregion
//缓存每个目录上次清理的文件最大的一个写入时间
var prevClearTime = new Dictionary();
foreach (var item in list)
{
prevClearTime[item] = DateTime.MinValue;
}
while (!stoppingToken.IsCancellationRequested)
{
logger.LogInformation($"开始数据清理...");
#region 从上次开始每个目录清理一定的数据(ClearHours)
int delFileCount = 0;
try
{
var driveFolders = list.GroupBy(m => Path.GetPathRoot(m).ToUpper());
foreach (var driveFolder in driveFolders)//like D:\ E:\
{
if (stoppingToken.IsCancellationRequested) break;
DriveInfo drive = new DriveInfo(driveFolder.Key);
while (drive.TotalFreeSpace / (drive.TotalSize * 1.0f) <= maxPercent)
{
foreach (var item in driveFolder)//like D:\data E:\data
{
logger.LogInformation($"正在清理[{item}]中的数据...");
var fsList = Directory.EnumerateFiles(item, "*", SearchOption.AllDirectories).Select(p => new FileInfo(p));
if (!fsList.Any())
{
logger.LogWarning($"{drive.ToString().Substring(0, 1)}盘空间不足,但目录{item}没有数据,跳过此目录");
}
else
{
if (prevClearTime[item] == DateTime.MinValue)
prevClearTime[item] = fsList.Min(p => p.LastWriteTime);
var maxTime = prevClearTime[item].AddHours(clearHours);
if (maxTime <= prevClearTime[item])
{
//clearHours配置为0或负数时一次删所有文件
maxTime = DateTime.MaxValue;
}
//每次清理从上次清理结束时间开始,防止有些删不掉的文件阻止删除文件
var clearFiles = fsList.Where(m => m.LastWriteTime >= prevClearTime[item] && m.LastWriteTime <= maxTime).OrderBy(m => m.LastWriteTime);
foreach (var fsItem in clearFiles)
{
try
{
if (stoppingToken.IsCancellationRequested) break;
fsItem.Delete();
delFileCount++;
}
catch (Exception ex)
{
logger.LogError($"删除文件{fsItem.Name}出错", ex);
}
}
prevClearTime[item] = maxTime;
}
}
}
}
}
catch (Exception ex)
{
logger.LogError("清理数据异常"+ex);
}
#endregion
#region 清理空目录
int delDirCount = 0;
foreach (var name in list)
{
string clearDir = Path.Combine(AppContext.BaseDirectory, name);
try
{
var dirs = Directory.EnumerateDirectories(clearDir, "*", SearchOption.AllDirectories);
foreach (var item in dirs)
{
DirectoryInfo dir = new DirectoryInfo(item);
if (dir.EnumerateFiles().Any()) continue;
//删除5分钟以前创建的空目录
if ((DateTime.Now - dir.CreationTime).TotalMinutes > 5)
{
try
{
dir.Delete();
delDirCount++;
}
catch (Exception ex)
{
logger.LogError($"删除空目录{dir.Name}异常", ex);
}
}
}
}
catch (Exception ex)
{
logger.LogError ($"删除{name}目录中的空目录出错", ex);
}
}
#endregion
logger.LogInformation($"本次清理数据结束,删除{delFileCount}个文件,删除{delDirCount}个空目录");
await Task.Delay(5 * 60 * 1000, stoppingToken);
}
}, stoppingToken);
}catch (Exception ex)
{
logger.LogError("数据清理服务异常" + ex.Message);
}
}
}
}