1. 删除指定文件夹底下的文件夹及文件
1.1 使用FileUtils删除
- 优点:使用工具类,代码干净,速度快
- 缺点:无法屏蔽一些不想删除或者根据条件删除文件,无法得知删除数量
1.1.1 引入依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
1.1.2 使用
File file = new File("/home/yhc/workSpace/log");
try {
FileUtils.deleteDirectory(file);
} catch (IOException e) {
e.printStackTrace();
}
1.1.3 其他功能
2.1 参数
参数名 | 含义 | 默认值 |
path | 删除的文件路径,支持多个路径,用 | 分割 |
PATH_PATTERN | 切割路径含有/[或[的正则表达式 | Pattern.compile(“^((?![\\/]\[).)*”) |
RULE_PATTERN | 切割路径含有[的正则表达式 | Pattern.compile(“\[.*”) |
days | 保留天数,超过此天数的文件将被删除 | 30 |
dayTimes | 一天的毫秒数 | 24 * 60 * 60 * 1000 |
ignoreName | 忽略的文件名,多个文件名用;分割 | 123.txt;123.log |
pathRetention | 是否按路径删除文件 | true |
下列为多线程特有参数 | ||
threadNum | 线程池大小 | 2 |
path入参必须含有yyyy mm dd 不区分大小写,/不区分。类似[YYYY]/[YYYYMM]/[YYYYMMDD]、[YYYY]/[MM]/[DD]、[YYYYMMDD]、[YYYY]/[YYYYMM]/[DD]等皆支持
2.2 代码(单线程)
package com.api.apidemo.tool.file;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author yhc
* @description 批量删除文件-普通方式
*/
public class BatchDeleteFile {
/**
* 删除的文件路径,支持多个路径,用|分割
*/
public static final String path = "/home/cathay10/workSpace/log/[yyyyMMdd]";
/**
* 切割路径含有/[或\[的正则表达式
*/
public static final Pattern PATH_PATTERN = Pattern.compile("^((?![\\\\/]\\[).)*");
/**
* 切割路径含有[的正则表达式
*/
public static final Pattern RULE_PATTERN = Pattern.compile("\\[.*");
/**
* 保留天数,超过此天数的文件将被删除
*/
public static final int days = 30;
/**
* 一天的毫秒数
*/
public static final int dayTimes = 24 * 60 * 60 * 1000;
/**
* 忽略的文件名,多个文件名用;分割
*/
public static final String ignoreName = "123.txt;123.log";
/**
* 是否按路径删除文件
*/
public static final boolean pathRetention = true;
public static void main(String[] args) {
long begin = System.currentTimeMillis();
long num = batchDeleteFile();
// 打印总删除文件数
long stop = System.currentTimeMillis();
System.out.println("执行结束,耗时:" + (stop - begin) + "ms" + " 删除文件数量:" + num);
}
/**
* 批量删除文件
*/
public static long batchDeleteFile() {
// 删除数量
long num = 0;
// 删除路径集合 有需要可以添加多个路径,按 | 分割
List sourceList = Arrays.asList(path.split("\\|"));
int length = sourceList.size();
if (length > 0) {
for (int m = 0; m < length; m++) {
// 判断目录是否含有日期格式
String targetPath = replaceDate(sourceList.get(m).toString());
// 处理通配符,将路径中的通配符替换为正则表达式
targetPath = replaceWildcard(targetPath);
if (pathRetention) {
// 按日期格式路径删除文件
// 截取掉除了年月日之外的路径
String dirPath = pathSplit(sourceList.get(m).toString());
File dir = new File(dirPath);
if (dir.exists()) {
// 当前日期
LocalDate nowDate = LocalDate.now();
String rule = ruleSplit(sourceList.get(m).toString());
num = num + judgeDocumentPath(dir, ignoreName, nowDate, rule);
}
} else {
String dirPath = pathSplit(targetPath);
// 按最后修改时间删除文件
File file = new File(dirPath);
if (file.exists()) {
num = num + judgeDocument(file, ignoreName);
}
}
}
}
return num;
}
/**
* 处理文件路径,替换日期格式占位符为当前日期
*
* @param path 原始路径
* @return 处理后的路径,如果没有找到日期占位符,则返回原路径
*/
public static String replaceDate(String path) {
String targetPath;
if (StringUtils.containsIgnoreCase(path, "[yyyy]/[MM]/[dd]")) {
targetPath = replaceIgnoreCase(path, "[yyyy]/[MM]/[dd]", LocalDate.now().toString().replace("-", "/"));
} else if (StringUtils.containsIgnoreCase(path, "[yyyyMMdd]")) {
targetPath = replaceIgnoreCase(path, "[yyyymmdd]", LocalDate.now().toString().replace("-", ""));
} else {
targetPath = path;
}
return targetPath;
}
/**
* 处理文件路径,将路径中的通配符替换为正则表达式
*
* @param path 原始路径
* @return 处理后的路径,如果没有找到通配符,则返回原路径
*/
public static String replaceWildcard(String path) {
path.replaceAll("\\*", ".*").replaceAll("\\?", ".");
return path;
}
/**
* 获取路径中是否包含日期格式
*
* @param targetPath 路径
* @return 处理后的路径,截取第一次遇到日期格式前的路径,如果没有找到有效的日期格式,则返回原路径
*/
public static String pathSplit(String targetPath) {
Matcher pathMatcher = PATH_PATTERN.matcher(targetPath);
while (pathMatcher.find()) {
if (pathMatcher.group() != null) {
return pathMatcher.group();
}
}
// 没有找到有效的日期
return null;
}
/**
* 获取路径中的日期规则正则
*
* @param targetPath 路径
* @return 规则正则
*/
public static String ruleSplit(String targetPath) {
Matcher ruleMatcher = RULE_PATTERN.matcher(targetPath);
String ruleContent;
while (ruleMatcher.find()) {
ruleContent = replaceCharsInSquareBrackets(ruleMatcher.group());
if (ruleContent != null) {
return ruleContent;
}
}
// 没有找到有效的日期
return null;
}
/**
* 替换方括号内的时间格式字符,分隔符[]
*
* @param str
* @return 替换后的字符串
*/
public static String replaceCharsInSquareBrackets(String str) {
// 正则表达式匹配方括号内的内容
String regex = "\\[(.*?)\\]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
// 存储原始和替换后的内容
List<String> originalMatches = new ArrayList<>();
List<String> replacedMatches = new ArrayList<>();
// 提取匹配的内容并进行替换
while (matcher.find()) {
originalMatches.add(matcher.group());
String match = matcher.group();
String match2 = match.replace("YYYY", "yyyy").replace("mm", "MM").replace("DD", "dd");
replacedMatches.add(match2);
}
// 将原始字符串分解,然后用替换后的内容替换匹配的子串
StringBuilder replacedStr = new StringBuilder(str);
for (int i = 0; i < originalMatches.size(); i++) {
int startIndex = replacedStr.indexOf(originalMatches.get(i));
int endIndex = startIndex + originalMatches.get(i).length();
replacedStr.replace(startIndex, endIndex, replacedMatches.get(i));
}
return replacedStr.toString().replaceAll("\\[", "").replaceAll("\\]", "");
}
/**
* 替换字符串,不区分大小写
*
* @param original 原始字符串
* @param from 要替换的字符串
* @param to 替换后的字符串
* @return 替换后的字符串
*/
public static String replaceIgnoreCase(String original, String from, String to) {
// 将要查找的字符串转换为正则表达式形式,并添加不区分大小写的标志(?i)
String regex = "(?i)" + Pattern.quote(from);
// 使用正则表达式进行替换
return original.replaceAll(regex, to);
}
/**
* 文件处理
*
* @param file 要处理的文件夹
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long judgeDocumentPath(File file, String ignoreName, LocalDate nowDate, String rule) {
long num = 0;
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
//调用方法循环完成对文件夹中文件的删除
Pattern PATH_RELE_PATTERN = Pattern.compile(rule.replaceAll("[/\\\\]", "[/\\\\\\\\]").replace("yyyy", "(\\d{4})").replace("MM", "(\\d{2})").replace("dd", "(\\d{2})"));
Matcher matcher = PATH_RELE_PATTERN.matcher(file1.getAbsolutePath());
if (matcher.find()) {
LocalDate pathDate = dateConversion(matcher.group(), rule);
long betweenDays = ChronoUnit.DAYS.between(pathDate, nowDate);
if (betweenDays > days) {
num = num + delFilePath(file1, ignoreName);
}
} else {
//调用方法循环完成对文件夹中文件的删除
num = num + judgeDocumentPath(file1, ignoreName, nowDate, rule);
}
}
}
return num;
}
/**
* 循环删除目录下的文件
*
* @param file 要删除的文件夹
* @return 处理的文件数量
*/
public static long delFilePath(File file, String ignoreName) {
long num = 0;
if (file.list().length < 1) {
deleteDirectoryPath(file);
} else {
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
num = num + delFilePath(file1, ignoreName);
} else if (!getIsNotLike(ignoreName, file1.getName())) {
file1.delete();
++num;
}
}
deleteDirectoryPath(file);
}
return num;
}
/**
* 删除文件夹
*
* @param files
*/
public static void deleteDirectoryPath(File files) {
if (files.exists() && files.list().length < 1) {
try {
Path path = files.toPath();
Files.delete(path);
deleteDirectoryPath(new File(path.getParent().toString()));
} catch (IOException e) {
}
}
}
/**
* 判断文件名中是否包含关键字,如果包含则剔除
*
* @param notLikeStr
* @param fileName
* @return
*/
public static boolean getIsNotLike(String notLikeStr, String fileName) {
String[] strArr = notLikeStr.split(";");
for (int i = 0; i < strArr.length; i++) {
if (fileName.contains(strArr[i])) {
return true;
}
}
return false;
}
/**
* 判断文件是否过期,如果过期则删除
*
* @param file 要处理的文件
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
private static long judgeDocument(File file, String ignoreName) {
long num = 0;
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
//调用方法循环完成对文件夹中文件的删除
num = num + delFile(file1, ignoreName);
} else {
num = num + analysisFiles(file1, ignoreName);
}
}
return num;
}
/**
* 判断文件是否过期,如果过期则删除
*
* @param file 要处理的文件
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long delFile(File file, String ignoreName) {
long num = 0;
if (file.list().length < 1) {
deleteDirectory(file);
} else {
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
num = num + delFile(file1, ignoreName);
} else {
num = num + analysisFiles(file1, ignoreName);
}
deleteDirectory(file);
}
}
return num;
}
/**
* 删除文件夹
*
* @param files 要删除的文件夹
*/
public static void deleteDirectory(File files) {
if (files.list().length < 1) {
try {
Path path = files.toPath();
Files.delete(path);
} catch (IOException e) {
}
}
}
/**
* 判断文件是否过期,如果过期则删除
*
* @param file 要处理的文件
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long analysisFiles(File file, String ignoreName) {
long num = 0;
//系统当前时间
double nowTime = System.currentTimeMillis();
Path path = file.toPath();
//根据创建时间和系统当前时间判断文件存在时间是否大于要求天数(CLEANTIMEs * 24 * 60 * 60 * 1000)
try {
BasicFileAttributeView basicView = Files.getFileAttributeView(path, BasicFileAttributeView.class);
BasicFileAttributes basicAttribs = basicView.readAttributes();
String fileName = file.getName();
if (getIsNotLike(ignoreName, fileName)) {
return 0;
}
//最后修改时间
Date savaTime = new Date(basicAttribs.lastModifiedTime().toMillis());
double saveTimes = savaTime.getTime();
if (nowTime - saveTimes > (double) days * dayTimes) {
Files.delete(path);
++num;
}
} catch (IOException e1) {
}
return num;
}
/**
* 转换日期格式,支持格式为:formats
*
* @param path 路径
* @return LocalDate 转换后的日期
*/
public static LocalDate dateConversion(String path, String rule) {
String[] formats = {rule.replace("\\", "/"), rule.replace("/", "\\")};
for (String format : formats) {
try {
LocalDate localDate = LocalDate.parse(path, DateTimeFormatter.ofPattern(format));
if (localDate != null) {
return localDate;
}
} catch (DateTimeParseException e) {
// 没有找到有效的日期
}
}
return null;
}
}
2.3 代码(线程池)
package com.api.apidemo.tool.file;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author yhc
* @description: 批量删除文件-多线程方式
*/
public class BatchDeleteFileThread {
/**
* 删除的文件路径,支持多个路径,用|分割
*/
public static final String path = "/home/cathay10/workSpace/log/[yyyy]/[MM]/[dd]";
/**
* 切割路径含有/[或\[的正则表达式
*/
public static final Pattern PATH_PATTERN = Pattern.compile("^((?![\\\\/]\\[).)*");
/**
* 切割路径含有[的正则表达式
*/
public static final Pattern RULE_PATTERN = Pattern.compile("\\[.*");
/**
* 保留天数,超过此天数的文件将被删除
*/
public static final int days = 30;
/**
* 一天的毫秒数
*/
public static final int dayTimes = 24 * 60 * 60 * 1000;
/**
* 线程池大小
*/
public static final int threadNum = 2;
/**
* 忽略的文件名,多个文件名用;分割
*/
public static final String ignoreName = "123.txt;123.log";
/**
* 是否按路径删除文件
*/
public static final boolean pathRetention = true;
public static void main(String[] args) {
long begin = System.currentTimeMillis();
long num = batchDeleteFile();
// 打印总删除文件数
long stop = System.currentTimeMillis();
System.out.println("执行结束,耗时:" + (stop - begin) + "ms" + " 删除文件数量:" + num);
}
/**
* 批量删除文件
*/
public static long batchDeleteFile() {
// 删除数量
long num = 0;
// 删除路径集合 有需要可以添加多个路径,按 | 分割
List sourceList = Arrays.asList(path.split("\\|"));
int length = sourceList.size();
if (length > 0) {
for (int m = 0; m < length; m++) {
// 判断目录是否含有日期格式
String targetPath = replaceDate(sourceList.get(m).toString());
// 处理通配符,将路径中的通配符替换为正则表达式
targetPath = replaceWildcard(targetPath);
if (pathRetention) {
// 按日期格式路径删除文件
// 截取掉除了年月日之外的路径
String dirPath = pathSplit(sourceList.get(m).toString());
File dir = new File(dirPath);
if (dir.exists()) {
// 当前日期
LocalDate nowDate = LocalDate.now();
String rule = ruleSplit(sourceList.get(m).toString());
num = num + judgeDocumentPath(dir, ignoreName, nowDate, rule);
}
} else {
String dirPath = pathSplit(targetPath);
// 按最后修改时间删除文件
File file = new File(dirPath);
if (file.exists()) {
num = num + judgeDocument(file, ignoreName);
}
}
}
}
return num;
}
/**
* 处理文件路径,替换日期格式占位符为当前日期
*
* @param path 原始路径
* @return 处理后的路径,如果没有找到日期占位符,则返回原路径
*/
public static String replaceDate(String path) {
String targetPath;
if (StringUtils.containsIgnoreCase(path, "[yyyy]/[MM]/[dd]")) {
targetPath = replaceIgnoreCase(path, "[yyyy]/[MM]/[dd]", LocalDate.now().toString().replace("-", "/"));
} else if (StringUtils.containsIgnoreCase(path, "[yyyyMMdd]")) {
targetPath = replaceIgnoreCase(path, "[yyyymmdd]", LocalDate.now().toString().replace("-", ""));
} else {
targetPath = path;
}
return targetPath;
}
/**
* 处理文件路径,将路径中的通配符替换为正则表达式
*
* @param path 原始路径
* @return 处理后的路径,如果没有找到通配符,则返回原路径
*/
public static String replaceWildcard(String path) {
path.replaceAll("\\*", ".*").replaceAll("\\?", ".");
return path;
}
/**
* 获取路径中是否包含日期格式,支持格式为:formats
*
* @param targetPath 路径
* @return 处理后的路径,截取第一次遇到日期格式前的路径,如果没有找到有效的日期格式,则返回原路径
*/
public static String pathSplit(String targetPath) {
Matcher pathMatcher = PATH_PATTERN.matcher(targetPath);
while (pathMatcher.find()) {
if (pathMatcher.group() != null) {
return pathMatcher.group();
}
}
// 没有找到有效的日期
return null;
}
/**
* 获取路径中的日期规则正则
*
* @param targetPath 路径
* @return 规则正则
*/
public static String ruleSplit(String targetPath) {
Matcher ruleMatcher = RULE_PATTERN.matcher(targetPath);
String ruleContent;
while (ruleMatcher.find()) {
ruleContent = replaceCharsInSquareBrackets(ruleMatcher.group());
if (ruleContent != null) {
return ruleContent;
}
}
// 没有找到有效的日期
return null;
}
/**
* 替换方括号内的时间格式字符,分隔符[]
*
* @param str
* @return 替换后的字符串
*/
public static String replaceCharsInSquareBrackets(String str) {
// 正则表达式匹配方括号内的内容
String regex = "\\[(.*?)\\]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
// 存储原始和替换后的内容
List<String> originalMatches = new ArrayList<>();
List<String> replacedMatches = new ArrayList<>();
// 提取匹配的内容并进行替换
while (matcher.find()) {
originalMatches.add(matcher.group());
String match = matcher.group();
String match2 = match.replace("YYYY", "yyyy").replace("mm", "MM").replace("DD", "dd");
replacedMatches.add(match2);
}
// 将原始字符串分解,然后用替换后的内容替换匹配的子串
StringBuilder replacedStr = new StringBuilder(str);
for (int i = 0; i < originalMatches.size(); i++) {
int startIndex = replacedStr.indexOf(originalMatches.get(i));
int endIndex = startIndex + originalMatches.get(i).length();
replacedStr.replace(startIndex, endIndex, replacedMatches.get(i));
}
return replacedStr.toString().replaceAll("\\[", "").replaceAll("\\]", "");
}
/**
* 替换字符串,不区分大小写
*
* @param original 原始字符串
* @param from 要替换的字符串
* @param to 替换后的字符串
* @return 替换后的字符串
*/
public static String replaceIgnoreCase(String original, String from, String to) {
// 将要查找的字符串转换为正则表达式形式,并添加不区分大小写的标志(?i)
String regex = "(?i)" + Pattern.quote(from);
// 使用正则表达式进行替换
return original.replaceAll(regex, to);
}
/**
* 文件处理
*
* @param file 要处理的文件夹
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long judgeDocumentPath(File file, String ignoreName, LocalDate nowDate, String rule) {
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
long num = 0;
File[] files = file.listFiles();
for (File file1 : files) {
Future<Long> future = executorService.submit(new DeleteFileCallable(pathRetention, file1, ignoreName, nowDate, rule));
try {
num = num + future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
// 关闭线程池
executorService.shutdown();
return num;
}
/**
* 文件处理
*
* @param file 要处理的文件夹
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long threadJudgeDocumentPath(File file, String ignoreName, LocalDate nowDate, String rule) {
long num = 0;
File[] files = file.listFiles();
if (file.isDirectory()) {
//调用方法循环完成对文件夹中文件的删除
Pattern PATH_RELE_PATTERN = Pattern.compile(rule.replaceAll("[/\\\\]", "[/\\\\\\\\]").replace("yyyy", "(\\d{4})").replace("MM", "(\\d{2})").replace("dd", "(\\d{2})"));
Matcher matcher = PATH_RELE_PATTERN.matcher(file.getAbsolutePath());
if (matcher.find()) {
LocalDate pathDate = dateConversion(matcher.group(), rule);
long betweenDays = ChronoUnit.DAYS.between(pathDate, nowDate);
if (betweenDays > days) {
num = num + delFilePath(file, ignoreName);
}
} else {
for (File file1 : files) {
//调用方法循环完成对文件夹中文件的删除
num = num + threadJudgeDocumentPath(file1, ignoreName, nowDate, rule);
}
}
}
return num;
}
/**
* 循环删除目录下的文件
*
* @param file 要删除的文件夹
* @return 处理的文件数量
*/
public static long delFilePath(File file, String ignoreName) {
long num = 0;
if (file.list().length < 1) {
deleteDirectoryPath(file);
} else {
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
num = num + delFilePath(file1, ignoreName);
} else if (!getIsNotLike(ignoreName, file1.getName())) {
file1.delete();
++num;
}
}
deleteDirectoryPath(file);
}
return num;
}
/**
* 删除文件夹
*
* @param files
*/
public static void deleteDirectoryPath(File files) {
if (files.exists() && files.list().length < 1) {
try {
Path path = files.toPath();
Files.delete(path);
deleteDirectoryPath(new File(path.getParent().toString()));
} catch (IOException e) {
}
}
}
/**
* 判断文件名中是否包含关键字,如果包含则剔除
*
* @param notLikeStr
* @param fileName
* @return
*/
public static boolean getIsNotLike(String notLikeStr, String fileName) {
String[] strArr = notLikeStr.split(";");
for (int i = 0; i < strArr.length; i++) {
if (fileName.contains(strArr[i])) {
return true;
}
}
return false;
}
/**
* 判断文件是否过期,如果过期则删除
*
* @param file 要处理的文件
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
private static long judgeDocument(File file, String ignoreName) {
ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
long num = 0;
File[] files = file.listFiles();
for (File file1 : files) {
Future<Long> future = executorService.submit(new DeleteFileCallable(pathRetention, file1, ignoreName, null, null));
try {
num = num + future.get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
// 关闭线程池
executorService.shutdown();
return num;
}
/**
* 判断文件是否过期,如果过期则删除
*
* @param file 要处理的文件
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
private static long threadJudgeDocument(File file, String ignoreName) {
long num = 0;
if (file.isDirectory()) {
//调用方法循环完成对文件夹中文件的删除
num = num + delFile(file, ignoreName);
} else {
num = num + analysisFiles(file, ignoreName);
}
return num;
}
/**
* 判断文件是否过期,如果过期则删除
*
* @param file 要处理的文件
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long delFile(File file, String ignoreName) {
long num = 0;
if (file.list().length < 1) {
deleteDirectory(file);
} else {
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
num = num + delFile(file1, ignoreName);
} else {
num = num + analysisFiles(file1, ignoreName);
}
deleteDirectory(file);
}
}
return num;
}
/**
* 删除文件夹
*
* @param files 要删除的文件夹
*/
public static void deleteDirectory(File files) {
if (files.list().length < 1) {
try {
Path path = files.toPath();
Files.delete(path);
} catch (IOException e) {
}
}
}
/**
* 判断文件是否过期,如果过期则删除
*
* @param file 要处理的文件
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long analysisFiles(File file, String ignoreName) {
long num = 0;
//系统当前时间
double nowTime = System.currentTimeMillis();
Path path = file.toPath();
//根据创建时间和系统当前时间判断文件存在时间是否大于要求天数(CLEANTIMEs * 24 * 60 * 60 * 1000)
try {
BasicFileAttributeView basicView = Files.getFileAttributeView(path, BasicFileAttributeView.class);
BasicFileAttributes basicAttribs = basicView.readAttributes();
String fileName = file.getName();
if (getIsNotLike(ignoreName, fileName)) {
return 0;
}
//最后修改时间
Date savaTime = new Date(basicAttribs.lastModifiedTime().toMillis());
double saveTimes = savaTime.getTime();
if (nowTime - saveTimes > (double) days * dayTimes) {
Files.delete(path);
++num;
}
} catch (IOException e1) {
}
return num;
}
/**
* 转换日期格式,支持格式为:formats
*
* @param path 路径
* @return LocalDate 转换后的日期
*/
public static LocalDate dateConversion(String path, String rule) {
String[] formats = {rule.replace("\\", "/"), rule.replace("/", "\\")};
for (String format : formats) {
try {
LocalDate localDate = LocalDate.parse(path, DateTimeFormatter.ofPattern(format));
if (localDate != null) {
return localDate;
}
} catch (DateTimeParseException e) {
// 没有找到有效的日期
}
}
return null;
}
static class DeleteFileCallable implements Callable<Long> {
private boolean pathRetention;
private File file;
private String ignoreName;
private LocalDate nowDate;
private String rule;
public DeleteFileCallable(boolean pathRetention, File file, String ignoreName, LocalDate nowDate, String rule) {
this.pathRetention = pathRetention;
this.file = file;
this.ignoreName = ignoreName;
this.nowDate = nowDate;
this.rule = rule;
}
@Override
public Long call() {
long num;
Thread currentThread = Thread.currentThread();
System.out.println("Thread ID: " + currentThread.getId() + " 文件路径:" + file.getAbsolutePath());
if (pathRetention) {
System.out.println("按日期格式路径删除文件");
num = threadJudgeDocumentPath(file, ignoreName, nowDate, rule);
} else {
System.out.println("按文件最后修改时间删除文件");
num = threadJudgeDocument(file, ignoreName);
}
return num;
}
}
}
2.4 代码(流)
package com.api.apidemo.tool.file;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* @author yhc
* @description 批量删除文件-流方式
*/
public class BatchDeleteFileStream {
/**
* 删除的文件路径,支持多个路径,用|分割
*/
public static final String path = "/home/cathay10/workSpace/log/[yyyy]/[MM]/[dd]";
/**
* 切割路径含有/[或\[的正则表达式
*/
public static final Pattern PATH_PATTERN = Pattern.compile("^((?![\\\\/]\\[).)*");
/**
* 切割路径含有[的正则表达式
*/
public static final Pattern RULE_PATTERN = Pattern.compile("\\[.*");
/**
* 保留天数,超过此天数的文件将被删除
*/
public static final int days = 30;
/**
* 一天的毫秒数
*/
// public static final int dayTimes = 24 * 60 * 60 * 1000;
public static final int dayTimes = 1000;
/**
* 忽略的文件名,多个文件名用;分割
*/
public static final String ignoreName = "123.txt;123.log";
/**
* 是否按路径删除文件
*/
public static final boolean pathRetention = true;
public static void main(String[] args) {
long begin = System.currentTimeMillis();
long num = batchDeleteFile();
// 打印总删除文件数
long stop = System.currentTimeMillis();
System.out.println("执行结束,耗时:" + (stop - begin) + "ms" + " 删除文件数量:" + num);
}
/**
* 批量删除文件
*/
public static long batchDeleteFile() {
// 删除数量
long num = 0;
// 删除路径集合 有需要可以添加多个路径,按 | 分割
List sourceList = Arrays.asList(path.split("\\|"));
int length = sourceList.size();
if (length > 0) {
for (int m = 0; m < length; m++) {
// 判断目录是否含有日期格式
String targetPath = replaceDate(sourceList.get(m).toString());
// 处理通配符,将路径中的通配符替换为正则表达式
targetPath = replaceWildcard(targetPath);
if (pathRetention) {
// 按日期格式路径删除文件
// 截取掉除了年月日之外的路径
String dirPath = pathSplit(sourceList.get(m).toString());
File dir = new File(dirPath);
if (dir.exists()) {
// 当前日期
LocalDate nowDate = LocalDate.now();
String rule = ruleSplit(sourceList.get(m).toString());
num = num + judgeDocumentPath(dir, ignoreName, nowDate, rule);
}
} else {
String dirPath = pathSplit(targetPath);
// 按最后修改时间删除文件
File file = new File(dirPath);
if (file.exists()) {
num = num + deleteFolder(file, ignoreName);
}
}
}
}
return num;
}
/**
* 处理文件路径,替换日期格式占位符为当前日期
*
* @param path 原始路径
* @return 处理后的路径,如果没有找到日期占位符,则返回原路径
*/
public static String replaceDate(String path) {
String targetPath;
if (StringUtils.containsIgnoreCase(path, "[yyyy]/[MM]/[dd]")) {
targetPath = replaceIgnoreCase(path, "[yyyy]/[MM]/[dd]", LocalDate.now().toString().replace("-", "/"));
} else if (StringUtils.containsIgnoreCase(path, "[yyyyMMdd]")) {
targetPath = replaceIgnoreCase(path, "[yyyymmdd]", LocalDate.now().toString().replace("-", ""));
} else {
targetPath = path;
}
return targetPath;
}
/**
* 处理文件路径,将路径中的通配符替换为正则表达式
*
* @param path 原始路径
* @return 处理后的路径,如果没有找到通配符,则返回原路径
*/
public static String replaceWildcard(String path) {
path.replaceAll("\\*", ".*").replaceAll("\\?", ".");
return path;
}
/**
* 获取路径中是否包含日期格式,支持格式为:formats
*
* @param targetPath 路径
* @return 处理后的路径,截取第一次遇到日期格式前的路径,如果没有找到有效的日期格式,则返回原路径
*/
public static String pathSplit(String targetPath) {
Matcher pathMatcher = PATH_PATTERN.matcher(targetPath);
while (pathMatcher.find()) {
if (pathMatcher.group() != null) {
return pathMatcher.group();
}
}
// 没有找到有效的日期
return null;
}
/**
* 获取路径中的日期规则正则
*
* @param targetPath 路径
* @return 规则正则
*/
public static String ruleSplit(String targetPath) {
Matcher ruleMatcher = RULE_PATTERN.matcher(targetPath);
String ruleContent;
while (ruleMatcher.find()) {
ruleContent = replaceCharsInSquareBrackets(ruleMatcher.group());
if (ruleContent != null) {
return ruleContent;
}
}
// 没有找到有效的日期
return null;
}
/**
* 替换方括号内的时间格式字符,分隔符[]
*
* @param str
* @return 替换后的字符串
*/
public static String replaceCharsInSquareBrackets(String str) {
// 正则表达式匹配方括号内的内容
String regex = "\\[(.*?)\\]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
// 存储原始和替换后的内容
List<String> originalMatches = new ArrayList<>();
List<String> replacedMatches = new ArrayList<>();
// 提取匹配的内容并进行替换
while (matcher.find()) {
originalMatches.add(matcher.group());
String match = matcher.group();
String match2 = match.replace("YYYY", "yyyy").replace("mm", "MM").replace("DD", "dd");
replacedMatches.add(match2);
}
// 将原始字符串分解,然后用替换后的内容替换匹配的子串
StringBuilder replacedStr = new StringBuilder(str);
for (int i = 0; i < originalMatches.size(); i++) {
int startIndex = replacedStr.indexOf(originalMatches.get(i));
int endIndex = startIndex + originalMatches.get(i).length();
replacedStr.replace(startIndex, endIndex, replacedMatches.get(i));
}
return replacedStr.toString().replaceAll("\\[", "").replaceAll("\\]", "");
}
/**
* 替换字符串,不区分大小写
*
* @param original 原始字符串
* @param from 要替换的字符串
* @param to 替换后的字符串
* @return 替换后的字符串
*/
public static String replaceIgnoreCase(String original, String from, String to) {
// 将要查找的字符串转换为正则表达式形式,并添加不区分大小写的标志(?i)
String regex = "(?i)" + Pattern.quote(from);
// 使用正则表达式进行替换
return original.replaceAll(regex, to);
}
/**
* 文件处理
*
* @param file 要处理的文件夹
* @param ignoreName 忽略文件名
* @return 处理的文件数量
*/
public static long judgeDocumentPath(File file, String ignoreName, LocalDate nowDate, String rule) {
long num = 0;
File[] files = file.listFiles();
for (File file1 : files) {
if (file1.isDirectory()) {
//调用方法循环完成对文件夹中文件的删除
Pattern PATH_RELE_PATTERN = Pattern.compile(rule.replaceAll("[/\\\\]", "[/\\\\\\\\]").replace("yyyy", "(\\d{4})").replace("MM", "(\\d{2})").replace("dd", "(\\d{2})"));
Matcher matcher = PATH_RELE_PATTERN.matcher(file1.getAbsolutePath());
if (matcher.find()) {
LocalDate pathDate = dateConversion(matcher.group(), rule);
long betweenDays = ChronoUnit.DAYS.between(pathDate, nowDate);
if (betweenDays > days) {
num = num + deleteFolderPath(file1, ignoreName);
}
} else {
//调用方法循环完成对文件夹中文件的删除
num = num + judgeDocumentPath(file1, ignoreName, nowDate, rule);
}
}
}
return num;
}
/**
* 判断文件名中是否包含关键字,如果包含则剔除
*
* @param notLikeStr
* @param fileName
* @return
*/
public static boolean getIsNotLike(String notLikeStr, String fileName) {
String[] strArr = notLikeStr.split(";");
for (int i = 0; i < strArr.length; i++) {
if (fileName.contains(strArr[i])) {
return true;
}
}
return false;
}
/**
* 删除文件夹下文件
*
* @param file 要删除的文件夹
* @param ignoreName 忽略文件名
* @return 删除的文件数量
*/
public static long deleteFolderPath(File file, String ignoreName) {
AtomicInteger i = new AtomicInteger();
// 路径
try (Stream<Path> stream = Files.walk(file.toPath())
.filter(path -> !path.toFile().isDirectory() && !getIsNotLike(ignoreName, path.getFileName().toString()))
.sorted(Comparator.reverseOrder())) {
stream.forEach(path -> {
// try {
Files.delete(path);
// if (Files.deleteIfExists(path)) {
i.incrementAndGet();
// }
// } catch (IOException e) {
// throw new RuntimeException(e);
// }
}
);
} catch (IOException e) {
e.printStackTrace();
}
return i.get();
}
/**
* 删除文件夹下文件
*
* @param file 要删除的文件夹
* @param ignoreName 忽略文件名
* @return 删除的文件数量
*/
public static long deleteFolder(File file, String ignoreName) {
double nowTime = System.currentTimeMillis();
AtomicInteger i = new AtomicInteger();
// 路径
try (Stream<Path> stream = Files.walk(file.toPath())
.sorted(Comparator.reverseOrder())) {
stream.forEachOrdered(path -> {
try {
//最后修改时间
Date savaTime = new Date(path.toFile().lastModified());
double saveTimes = savaTime.getTime();
//获取非文件夹获取修改时间,因为删除文件时,会修改文件夹的最后修改时间,导致无法删除
if (!path.toFile().isDirectory() && !getIsNotLike(ignoreName, path.getFileName().toString()) && nowTime - saveTimes > (double) days * dayTimes) {
boolean deleteSuccess = Files.deleteIfExists(path);
if (deleteSuccess) {
i.incrementAndGet();
}
} else if (path.toFile().listFiles().length == 0) {
Files.deleteIfExists(path);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
});
} catch (IOException e) {
e.printStackTrace();
}
return i.get();
}
/**
* 转换日期格式,支持格式为:formats
*
* @param path 路径
* @return LocalDate 转换后的日期
*/
public static LocalDate dateConversion(String path, String rule) {
String[] formats = {rule.replace("\\", "/"), rule.replace("/", "\\")};
for (String format : formats) {
try {
LocalDate localDate = LocalDate.parse(path, DateTimeFormatter.ofPattern(format));
if (localDate != null) {
return localDate;
}
} catch (DateTimeParseException e) {
// 没有找到有效的日期
}
}
return null;
}
}
3. 问题调整
3.1 如需严格按照文件名称删除,在正则里添加必须按正则结尾去处理
例子:之前的代码会删除如 20240505-副本的文件夹,更新成新的后,将不会删除
Pattern PATH_RELE_PATTERN = Pattern.compile("(" + rule.replaceAll("[/\\\\]", "[/\\\\\\\\]").replace("yyyy", "(\\d{4})").replace("MM", "(\\d{2})").replace("dd", "(\\d{2})") + ")$");