CearDirService.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. using AdService.Controller.Dto;
  2. using Newtonsoft.Json;
  3. namespace AdService.Service
  4. {
  5. /// <summary>
  6. /// 数据清理服务(每隔5分钟扫描一次)
  7. /// </summary>
  8. public class CearDirService : BackgroundService
  9. {
  10. ILogger logger { get; set; }
  11. /// <summary>
  12. /// 数据清理服务
  13. /// </summary>
  14. protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  15. {
  16. try
  17. {
  18. await Task.Delay(5000, stoppingToken);//延迟一会儿让webbapi先启动
  19. await Task.Run(async () =>
  20. {
  21. #region 读取清理目录配置信息
  22. StreamReader sr = new StreamReader(Directory.GetCurrentDirectory() + "appsettings.json");
  23. string json = sr.ReadToEnd();
  24. // 解析 JSON 字符串
  25. var adConfig = JsonConvert.DeserializeObject<AdConfig>(json);
  26. string dataClearStr = adConfig.ClearDir;
  27. var dataClears = dataClearStr.Split(new string[] { ";", ";" }, StringSplitOptions.RemoveEmptyEntries)
  28. .Select(p => p.ToLower()).ToList();
  29. if (!dataClears.Contains(adConfig.DataDir))
  30. dataClears.Add(adConfig.DataDir);
  31. #endregion
  32. #region 检测有效的清理目录并读取清理条件
  33. List<string> list = new List<string>();
  34. foreach (var item in dataClears)
  35. {
  36. var root = Path.GetPathRoot(item);
  37. DriveInfo drive = new DriveInfo(root);
  38. if (!drive.IsReady)
  39. {
  40. continue;
  41. }
  42. if (Directory.Exists(item))
  43. {
  44. list.Add(item);
  45. }
  46. }
  47. if (!list.Any())
  48. {
  49. logger.LogWarning($"配置文件中的数据清理目录无效");
  50. return;
  51. }
  52. float maxPercent = adConfig.ClearCondition;
  53. var clearHours = adConfig.ClearHours;
  54. if (clearHours < 1)
  55. {
  56. clearHours = 1;
  57. }
  58. logger.LogInformation($"已启动目录[{string.Join(";", list)}]自动清理,清理条件=可用空间不足{(int)(maxPercent * 100)}%");
  59. #endregion
  60. //缓存每个目录上次清理的文件最大的一个写入时间
  61. var prevClearTime = new Dictionary<string, DateTime>();
  62. foreach (var item in list)
  63. {
  64. prevClearTime[item] = DateTime.MinValue;
  65. }
  66. while (!stoppingToken.IsCancellationRequested)
  67. {
  68. logger.LogInformation($"开始数据清理...");
  69. #region 从上次开始每个目录清理一定的数据(ClearHours)
  70. int delFileCount = 0;
  71. try
  72. {
  73. var driveFolders = list.GroupBy(m => Path.GetPathRoot(m).ToUpper());
  74. foreach (var driveFolder in driveFolders)//like D:\ E:\
  75. {
  76. if (stoppingToken.IsCancellationRequested) break;
  77. DriveInfo drive = new DriveInfo(driveFolder.Key);
  78. while (drive.TotalFreeSpace / (drive.TotalSize * 1.0f) <= maxPercent)
  79. {
  80. foreach (var item in driveFolder)//like D:\data E:\data
  81. {
  82. logger.LogInformation($"正在清理[{item}]中的数据...");
  83. var fsList = Directory.EnumerateFiles(item, "*", SearchOption.AllDirectories).Select(p => new FileInfo(p));
  84. if (!fsList.Any())
  85. {
  86. logger.LogWarning($"{drive.ToString().Substring(0, 1)}盘空间不足,但目录{item}没有数据,跳过此目录");
  87. }
  88. else
  89. {
  90. if (prevClearTime[item] == DateTime.MinValue)
  91. prevClearTime[item] = fsList.Min(p => p.LastWriteTime);
  92. var maxTime = prevClearTime[item].AddHours(clearHours);
  93. if (maxTime <= prevClearTime[item])
  94. {
  95. //clearHours配置为0或负数时一次删所有文件
  96. maxTime = DateTime.MaxValue;
  97. }
  98. //每次清理从上次清理结束时间开始,防止有些删不掉的文件阻止删除文件
  99. var clearFiles = fsList.Where(m => m.LastWriteTime >= prevClearTime[item] && m.LastWriteTime <= maxTime).OrderBy(m => m.LastWriteTime);
  100. foreach (var fsItem in clearFiles)
  101. {
  102. try
  103. {
  104. if (stoppingToken.IsCancellationRequested) break;
  105. fsItem.Delete();
  106. delFileCount++;
  107. }
  108. catch (Exception ex)
  109. {
  110. logger.LogError($"删除文件{fsItem.Name}出错", ex);
  111. }
  112. }
  113. prevClearTime[item] = maxTime;
  114. }
  115. }
  116. }
  117. }
  118. }
  119. catch (Exception ex)
  120. {
  121. logger.LogError("清理数据异常"+ex);
  122. }
  123. #endregion
  124. #region 清理空目录
  125. int delDirCount = 0;
  126. foreach (var name in list)
  127. {
  128. string clearDir = Path.Combine(AppContext.BaseDirectory, name);
  129. try
  130. {
  131. var dirs = Directory.EnumerateDirectories(clearDir, "*", SearchOption.AllDirectories);
  132. foreach (var item in dirs)
  133. {
  134. DirectoryInfo dir = new DirectoryInfo(item);
  135. if (dir.EnumerateFiles().Any()) continue;
  136. //删除5分钟以前创建的空目录
  137. if ((DateTime.Now - dir.CreationTime).TotalMinutes > 5)
  138. {
  139. try
  140. {
  141. dir.Delete();
  142. delDirCount++;
  143. }
  144. catch (Exception ex)
  145. {
  146. logger.LogError($"删除空目录{dir.Name}异常", ex);
  147. }
  148. }
  149. }
  150. }
  151. catch (Exception ex)
  152. {
  153. logger.LogError ($"删除{name}目录中的空目录出错", ex);
  154. }
  155. }
  156. #endregion
  157. logger.LogInformation($"本次清理数据结束,删除{delFileCount}个文件,删除{delDirCount}个空目录");
  158. await Task.Delay(5 * 60 * 1000, stoppingToken);
  159. }
  160. }, stoppingToken);
  161. }catch (Exception ex)
  162. {
  163. logger.LogError("数据清理服务异常" + ex.Message);
  164. }
  165. }
  166. }
  167. }