java - 如何删除目录中的所有重复文件?爪哇
问题描述
我如何编写代码才能准确删除我之前使用此代码获得的重复项。??请具体回答,因为我是java新手。我对java有非常基本的了解。
private static MessageDigest messageDigest;
static {
try {
messageDigest = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("cannot initialize SHA-512 hash function", e);
}
}
public static void findDuplicatedFiles(Map<String, List<String>> lists, File directory) {
for (File child : directory.listFiles()) {
if (child.isDirectory()) {
findDuplicatedFiles(lists, child);
} else {
try {
FileInputStream fileInput = new FileInputStream(child);
byte fileData[] = new byte[(int) child.length()];
fileInput.read(data);
fileInput.close();
String uniqueFileHash = new BigInteger(1, md.digest(fileData)).toString(16);
List<String> list = lists.get(uniqueFileHash);
if (list == null) {
list = new LinkedList<String>();
lists.put(uniqueFileHash, list);
}
list.add(child.getAbsolutePath());
} catch (IOException e) {
throw new RuntimeException("cannot read file " + child.getAbsolutePath(), e);
}
}
}
}
Map<String, List<String>> lists = new HashMap<String, List<String>>();
FindDuplicates.findDuplicateFiles(lists, dir);
for (List<String> list : lists.values()) {
if (list.size() > 1) {
System.out.println("\n");
for (String file : list) {
System.out.println(file);
}
}
}
System.out.println("\n");
解决方案
Path
使用 NIO / class扫描目录更容易,Files
因为它避免了类的尴尬递归File
,并且对于更深的目录树来说更快。
这是一个示例扫描器,它返回一个Stream
重复项 - 即流中的每个项目都是一个List<Path>
- 一组两个或更多相同的文件。
// Scan a directory and returns Stream of List<Path> where each list has 2 or more duplicates
static Stream<List<Path>> findDuplicates(Path dir) throws IOException {
Map<Long, List<Path>> candidates = new HashMap<>();
BiPredicate<Path, BasicFileAttributes> biPredicate = (p,a)->a.isRegularFile()
&& candidates.computeIfAbsent(Long.valueOf(a.size())
, k -> new ArrayList<>()).add(p);
try(var stream = Files.find(dir, Integer.MAX_VALUE, biPredicate)) {
stream.count();
}
Predicate<? super List<Path>> twoOrMore = paths -> paths.size() > 1;
return candidates.values().stream()
.filter(twoOrMore)
.flatMap(Duplicate::duplicateChecker)
.filter(twoOrMore);
}
上面的代码首先整理具有相同文件大小的候选者,然后使用一个flatMap
操作来比较所有这些候选者以获得完全匹配的文件,其中每个文件都相同List<Path>
:
// Checks possible list of duplicates, and returns stream of definite duplicates
private static Stream<List<Path>> duplicateChecker(List<Path> sameLenPaths) {
List<List<Path>> groups = new ArrayList<>();
try {
for (Path p : sameLenPaths) {
List<Path> match = null;
for (List<Path> g : groups) {
Path prev = g.get(0);
if(Files.mismatch(prev, p) < 0) {
match = g;
break;
}
}
if (match == null)
groups.add(match = new ArrayList<>());
match.add(p);
}
} catch(IOException io) {
throw new UncheckedIOException(io);
}
return groups.stream();
}
最后是一个示例启动器:
public static void main(String[] args) throws IOException {
Path dir = Path.of(args[0]);
Stream<List<Path>> duplicates = findDuplicates(dir);
long count = duplicates.peek(System.out::println).count();
System.out.println("Found "+count+" groups of duplicate files in: "+dir);
}
您将需要使用Files.delete
- 我没有Files.delete
在末尾添加来处理重复文件列表,以便您可以在决定删除它们之前检查结果。
// findDuplicates(dir).flatMap(List::stream).forEach(dup -> {
// try {
// Files.delete(dup);
// } catch(IOException io) {
// throw new UncheckedIOException(io);
// }
// });
推荐阅读
- c# - 在我们的 .net 项目中更改 MSBuild 工具集 (ToolsVersion) 的缺点是什么?
- typescript - 使用反应表 CellPropGetter
- linux - Netcat:使用脚本测试端口是否从给定的源主机打开到使用 netcat 的远程主机
- xamarin - 有没有办法可以使用 Xamarin 表单向 Shell 选项卡区域添加左右边距?
- pyspark - 当一列中的值在另一列中时标记数据
- android - 检索访问令牌 Firebase
- java - Spring boot 2.2.0 测试:配置错误:发现@BootstrapWith 的多个声明
- javascript - 如果选择编辑,如何隐藏组件
- python - 我在特定频道的工作脚本有问题
- android - 未请求相机权限,但仍在工作