未测试的定时删除功能

南通通威
LAPTOP-S9HJSOEB\昊天 10 months ago
parent 621ad8078b
commit bdd31f0584

@ -129,6 +129,14 @@
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

@ -25,19 +25,21 @@ import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import static java.nio.file.FileVisitResult.CONTINUE;
@Component
@EnableScheduling
@ -170,7 +172,133 @@ public class CronTab {
}
}
}
private static List<File> getSortedFoldersByCreateTime(File parentDir) {
File[] folders = parentDir.listFiles(File::isDirectory);
if (folders == null || folders.length == 0) {
return Collections.emptyList();
}
return Arrays.stream(folders)
.filter(f -> {
try {
Path path = f.toPath();
BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class);
return attr != null && attr.creationTime() != null;
} catch (IOException e) {
return false;
}
})
.sorted(Comparator.comparingLong(f -> {
try {
return Files.readAttributes(f.toPath(), BasicFileAttributes.class).creationTime().toMillis();
} catch (IOException e) {
return Long.MAX_VALUE;
}
}))
.collect(Collectors.toList());
}
/**
* 350GB
*
* @param dirPath
*/
public static void deleteUntilFreeSpace(String dirPath) {
File rootDir = new File(dirPath);
if (!rootDir.exists() || !rootDir.isDirectory()) {
log.warn("目标路径不存在或不是目录: {}", dirPath);
return;
}
while (true) {
long freeSpaceGB = rootDir.getFreeSpace() / (1024L * 1024L * 1024L);
if (freeSpaceGB > 350) {
log.info("磁盘空间已满足要求: {} GB", freeSpaceGB);
break;
}
// 获取所有可删除的文件和空文件夹,并按创建时间排序
List<Path> deletableItems = findDeletableItemsSortedByCreateTime(rootDir);
if (deletableItems.isEmpty()) {
log.warn("没有更多可删除的文件或文件夹");
break;
}
// 删除最早的项
Path oldestItem = deletableItems.get(0);
try {
Files.walk(oldestItem)
.sorted(Comparator.reverseOrder())
.forEach(path -> {
try {
Files.delete(path);
log.info("已删除: {}", path);
} catch (IOException e) {
log.error("删除失败: {}", path, e);
}
});
} catch (Exception e) {
log.error("删除路径时出错: {}", oldestItem, e);
}
}
}
private static class PathWithCreateTime {
Path path;
long createTime;
PathWithCreateTime(Path path, long createTime) {
this.path = path;
this.createTime = createTime;
}
}
/**
*
*/
private static List<Path> findDeletableItemsSortedByCreateTime(File rootDir) {
List<PathWithCreateTime> candidates = new ArrayList<>();
try {
Files.walkFileTree(rootDir.toPath(), new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (attrs.isRegularFile()) {
candidates.add(new PathWithCreateTime(file, attrs.creationTime().toMillis()));
}
return CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
if (exc != null) {
return CONTINUE;
}
try {
// 只收集空文件夹
if (Files.list(dir).findAny().isEmpty()) {
BasicFileAttributes attrs = Files.readAttributes(dir, BasicFileAttributes.class);
candidates.add(new PathWithCreateTime(dir, attrs.creationTime().toMillis()));
}
} catch (IOException e) {
log.warn("读取文件夹失败: {}", dir, e);
}
return CONTINUE;
}
});
} catch (IOException e) {
log.error("遍历文件系统时出错", e);
}
return candidates.stream()
.sorted(Comparator.comparingLong(p -> p.createTime))
.map(p -> p.path)
.collect(Collectors.toList());
}
public static void main(String[] args) {
deleteUntilFreeSpace("D:\\data");
}
public static void deleteOldFoldersByName(File parentDir, int days) {
if (!parentDir.exists() || !parentDir.isDirectory()) {
System.out.println("指定的路径不是一个有效的目录: " + parentDir.getName());

@ -0,0 +1,149 @@
package com.zhehekeji.web.service;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import static java.nio.file.FileVisitResult.CONTINUE;
@Slf4j
public class CronTabDelete {
private static final long MIN_FREE_SPACE_GB = 350;
private static final long GB = 1024L * 1024L * 1024L;
private static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;
private static final ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
/**
* GB
*/
public static void deleteUntilFreeSpace(String dirPath) {
File rootDir = new File(dirPath);
if (!rootDir.exists() || !rootDir.isDirectory()) {
log.warn("目标路径不存在或不是目录: {}", dirPath);
return;
}
while (true) {
long freeSpaceGB = rootDir.getFreeSpace() / GB;
if (freeSpaceGB > MIN_FREE_SPACE_GB) {
log.info("磁盘空间已满足要求: {} GB", freeSpaceGB);
break;
}
List<Path> deletableItems = findDeletableItemsSortedByCreateTime(rootDir);
if (deletableItems.isEmpty()) {
log.warn("没有更多可删除的文件或文件夹");
break;
}
// 批量删除前 N 个最老项(例如 100 个)
int batchSize = Math.min(deletableItems.size(), 100);
List<Path> batchToDelete = deletableItems.subList(0, batchSize);
log.info("准备删除 {} 个最旧文件/空文件夹", batchToDelete.size());
List<Future<?>> futures = new ArrayList<>();
for (Path path : batchToDelete) {
futures.add(executor.submit(() -> deleteRecursively(path)));
}
// 等待所有任务完成
for (Future<?> future : futures) {
try {
future.get();
} catch (Exception e) {
log.error("并发删除失败", e);
}
}
}
}
/**
*
*/
private static void deleteRecursively(Path path) {
try {
Files.walk(path)
.sorted(Comparator.reverseOrder())
.forEach(p -> {
try {
Files.delete(p);
log.debug("已删除: {}", p);
} catch (IOException e) {
log.warn("删除失败: {}", p);
}
});
} catch (IOException e) {
log.warn("遍历路径失败: {}", path, e);
}
}
/**
*
*/
private static List<Path> findDeletableItemsSortedByCreateTime(File rootDir) {
List<PathWithCreateTime> candidates = Collections.synchronizedList(new ArrayList<>());
ForkJoinPool forkJoinPool = new ForkJoinPool(THREAD_POOL_SIZE);
try {
forkJoinPool.submit(() -> {
try {
Files.walkFileTree(rootDir.toPath(), EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (attrs.isRegularFile()) {
candidates.add(new PathWithCreateTime(file, attrs.creationTime().toMillis()));
}
return CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
if (exc != null) return CONTINUE;
try {
if (Files.list(dir).findAny().isEmpty()) {
BasicFileAttributes attrs = Files.readAttributes(dir, BasicFileAttributes.class);
candidates.add(new PathWithCreateTime(dir, attrs.creationTime().toMillis()));
}
} catch (IOException e) {
log.warn("读取文件夹失败: {}", dir, e);
}
return CONTINUE;
}
});
} catch (IOException e) {
log.error("遍历文件系统时出错", e);
}
}).join();
} finally {
forkJoinPool.shutdown();
}
return candidates.parallelStream()
.sorted(Comparator.comparingLong(p -> p.createTime))
.map(p -> p.path)
.collect(Collectors.toList());
}
private static class PathWithCreateTime {
Path path;
long createTime;
PathWithCreateTime(Path path, long createTime) {
this.path = path;
this.createTime = createTime;
}
}
public static void main(String[] args) {
deleteUntilFreeSpace("D:\\data\\videos");
}
}
Loading…
Cancel
Save