package com.threecloud.dataserviceyy.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; /** * 文件清理工具类 * 负责清理过期的本地录音文件 * * 【目录结构】 * vaa-recordings/ * ├── 340100/ # 地市编码 * │ ├── 20240101/ # 日期目录 * │ │ └── / # 设备目录 * │ │ └── xxx.wav * │ └── 20240102/ * │ └── ... * ├── 340200/ * └── .sync-marker/ */ public class FileCleaner { private static final Logger logger = LoggerFactory.getLogger(FileCleaner.class); /** * 默认保留天数 */ private static final int DEFAULT_RETAIN_DAYS = 10; /** * 日期格式 */ private static final String DATE_FORMAT = "yyyyMMdd"; /** * 地市编码正则(6位数字) */ private static final String CITY_CODE_PATTERN = "\\d{6}"; /** * 清理指定天数前的本地录音文件 * * 清理逻辑: * 1. 遍历 basePath 下地市目录(如 340100, 340200) * 2. 遍历每个地市目录下的日期目录(如 20240101) * 3. 删除早于 cutoffDate 的日期目录 * * @param basePath 基础路径 * @param retainDays 保留天数 */ public static void cleanOldFiles(String basePath, int retainDays) { File baseDir = new File(basePath); if (!baseDir.exists() || !baseDir.isDirectory()) { logger.debug("基础目录不存在或不是目录: {}", basePath); return; } // 获取地市目录列表 File[] cityDirs = baseDir.listFiles(File::isDirectory); if (cityDirs == null || cityDirs.length == 0) { logger.debug("目录下没有地市子目录: {}", basePath); return; } String cutoffDate = calculateCutoffDate(retainDays); int totalDeletedCount = 0; for (File cityDir : cityDirs) { String cityCode = cityDir.getName(); // 跳过非地市目录(如 .sync-marker) if (!cityCode.matches(CITY_CODE_PATTERN)) { logger.debug("跳过非地市目录: {}", cityCode); continue; } // 清理该地市下的过期日期目录 int deletedCount = cleanCityDirectory(cityDir, cutoffDate); totalDeletedCount += deletedCount; // 如果地市目录为空,删除地市目录 if (deletedCount > 0 && isEmptyDirectory(cityDir)) { cityDir.delete(); logger.info("已删除空地市目录: {}", cityDir.getAbsolutePath()); } } if (totalDeletedCount > 0) { logger.info("清理完成,共删除 {} 个过期日期目录", totalDeletedCount); } else { logger.debug("没有需要清理的过期文件"); } } /** * 清理指定地市目录下的过期日期目录 * * @param cityDir 地市目录 * @param cutoffDate 截止日期 * @return 删除的目录数 */ private static int cleanCityDirectory(File cityDir, String cutoffDate) { File[] dateDirs = cityDir.listFiles(File::isDirectory); if (dateDirs == null || dateDirs.length == 0) { return 0; } int deletedCount = 0; for (File dateDir : dateDirs) { String dirName = dateDir.getName(); // 只处理日期格式的目录(如 20240101) if (dirName.matches("\\d{8}") && dirName.compareTo(cutoffDate) < 0) { if (deleteDirectory(dateDir)) { deletedCount++; logger.info("已清理过期录音目录: {} (早于 {})", dateDir.getAbsolutePath(), cutoffDate); } } } return deletedCount; } /** * 检查目录是否为空(不包含任何文件和子目录) * * @param dir 目录 * @return 是否为空 */ private static boolean isEmptyDirectory(File dir) { File[] files = dir.listFiles(); return files == null || files.length == 0; } /** * 清理默认天数(10天)前的文件 * * @param basePath 基础路径 */ public static void cleanOldFiles(String basePath) { cleanOldFiles(basePath, DEFAULT_RETAIN_DAYS); } /** * 递归删除目录 * * @param dir 要删除的目录 * @return 是否成功删除 */ private static boolean deleteDirectory(File dir) { File[] files = dir.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory()) { deleteDirectory(file); } else { file.delete(); } } } return dir.delete(); } /** * 计算截止日期 * * @param retainDays 保留天数 * @return 截止日期字符串(yyyyMMdd) */ private static String calculateCutoffDate(int retainDays) { Date cutoffDate = DateUtil.addDayByDate(new Date(), -retainDays); return new SimpleDateFormat(DATE_FORMAT).format(cutoffDate); } }