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); } } } }