From df39df55d77dd07c2899b8b8c6273c038c38ba66 Mon Sep 17 00:00:00 2001 From: CXT-maker <19235211755@163.com> Date: Mon, 17 Nov 2025 20:29:11 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AD=A5=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=80=BB=E6=95=B0=E5=88=86=E7=B1=BB=20=E7=AC=AC=E4=BA=8C?= =?UTF-8?q?=E6=AD=A5=E6=B7=BB=E5=8A=A0=E2=80=9C=E7=94=9F=E6=88=90=E7=89=A9?= =?UTF-8?q?=E7=90=86=E5=9C=B0=E5=9D=80=E6=96=87=E4=BB=B6=E2=80=9D=E7=9A=84?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E9=87=8D=E5=A4=8D=E6=96=87=E4=BB=B6=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../JavaFxApplication.java | 2 +- .../core/DuplicateFinder.java | 32 +++ .../core/LogicalAddressFileGenerator.java | 46 +++- .../core/PhysicalAddressFileGenerator.java | 211 +++++++++++++++--- .../ui/module/PathCheckPaneController.java | 4 +- .../ui/task/AddressFileGenerationTask.java | 7 + .../task/DuplicateDocumentDetectionTask.java | 76 ++++--- 8 files changed, 297 insertions(+), 83 deletions(-) diff --git a/build.gradle b/build.gradle index d461f6c..5c47a86 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.github.albfernandez:javadbf:1.14.1' implementation 'org.apache.poi:poi-ooxml:5.4.1' implementation 'com.intellij:annotations:12.0' - + implementation 'org.ofdrw:ofdrw-reader:2.3.7' compileOnly 'org.projectlombok:lombok:1.18.38' annotationProcessor 'org.projectlombok:lombok:1.18.38' diff --git a/src/main/java/top/r3944realms/docchecktoolrefactored/JavaFxApplication.java b/src/main/java/top/r3944realms/docchecktoolrefactored/JavaFxApplication.java index 7b5b404..3ff07d3 100644 --- a/src/main/java/top/r3944realms/docchecktoolrefactored/JavaFxApplication.java +++ b/src/main/java/top/r3944realms/docchecktoolrefactored/JavaFxApplication.java @@ -12,7 +12,7 @@ public class JavaFxApplication extends Application { @Override public void init() throws Exception { super.init(); - System.setVersion("1.0.0.5"); + System.setVersion("1.0"); } @Override diff --git a/src/main/java/top/r3944realms/docchecktoolrefactored/core/DuplicateFinder.java b/src/main/java/top/r3944realms/docchecktoolrefactored/core/DuplicateFinder.java index fc58442..bdc893c 100644 --- a/src/main/java/top/r3944realms/docchecktoolrefactored/core/DuplicateFinder.java +++ b/src/main/java/top/r3944realms/docchecktoolrefactored/core/DuplicateFinder.java @@ -31,6 +31,17 @@ public class DuplicateFinder { private final FileHashCalculator hashCalculator; private final boolean enableProgress; private final ExecutorService executorService; + private final AtomicInteger targetFiles = new AtomicInteger(0); + private final AtomicInteger otherFiles = new AtomicInteger(0); + +// Add getter methods +public int getTargetFilesCount() { + return targetFiles.get(); +} + +public int getOtherFilesCount() { + return otherFiles.get(); +} // 进度回调接口 public interface ProgressCallback { default void onPhaseStarted(Phase phase) {} @@ -71,6 +82,8 @@ public class DuplicateFinder { public List findDuplicates(Path rootDir) throws IOException { // 清理错误列表 errors.clear(); + targetFiles.set(0); + otherFiles.set(0); // ----------------------------- // 第一阶段:按文件大小分组 // ----------------------------- @@ -154,6 +167,25 @@ public class DuplicateFinder { meta.setPath(file); meta.setSize(Files.size(file)); sizeGroups.computeIfAbsent(meta.getSize(), k -> new ArrayList<>()).add(meta); + + // Classify and count files + String fileName = file.getFileName().toString().toLowerCase(); + String extension = ""; + int lastDotIndex = fileName.lastIndexOf('.'); + if (lastDotIndex > 0) { + extension = fileName.substring(lastDotIndex + 1); + } + + // Check if it's a target file + if ("pdf".equals(extension) || "ofd".equals(extension) || + "jpg".equals(extension) || "jpeg".equals(extension) || + "png".equals(extension) || "bmp".equals(extension) || + "gif".equals(extension) || "tiff".equals(extension) || + "jp2".equals(extension)) { + targetFiles.incrementAndGet(); + } else { + otherFiles.incrementAndGet(); + } } catch (IOException e) { log.error(LoggerMarker.TRACE_MARKER, "Failed to get file's size: {}", file); } diff --git a/src/main/java/top/r3944realms/docchecktoolrefactored/core/LogicalAddressFileGenerator.java b/src/main/java/top/r3944realms/docchecktoolrefactored/core/LogicalAddressFileGenerator.java index 37b37df..61f8a6e 100644 --- a/src/main/java/top/r3944realms/docchecktoolrefactored/core/LogicalAddressFileGenerator.java +++ b/src/main/java/top/r3944realms/docchecktoolrefactored/core/LogicalAddressFileGenerator.java @@ -98,6 +98,7 @@ public class LogicalAddressFileGenerator implements AddressFileGenerator { errorMsg.append(code).append("\n"); } log.info(LoggerMarker.RELEASE_MARKER, "{}", errorMsg.toString()); + throw new RuntimeException(errorMsg.toString()); }else { // 写入CSV头部 @@ -132,22 +133,43 @@ public class LogicalAddressFileGenerator implements AddressFileGenerator { * 生成文件级逻辑地址文件 */ private void generateFileLevelFile(PrintWriter writer, List records, ProgressCallback callback) { - // 写入CSV头部(包含页数列) - writer.println("逻辑文件名,逻辑地址,页数"); - int totalRecords = records.stream().mapToInt(r -> r.page).sum(); - int current = 0; - - // 处理每条记录 + Set seenCodes = new HashSet<>(); + Set duplicateCodes = new HashSet<>(); + // 收集所有重复的档号 for (Record record : records) { String archiveCode = record.archiveCode; - int page = record.page; + if (!seenCodes.add(archiveCode)) { + duplicateCodes.add(archiveCode); + } + } - // 生成逻辑地址(不包含页数) - String logicalAddress = generateFileLevelLogicalAddress(archiveCode); + // 如果存在重复档号,记录日志并抛出异常 + if (!duplicateCodes.isEmpty()) { + StringBuilder errorMsg = new StringBuilder("存在重复档号:\n"); + for (String code : duplicateCodes) { + errorMsg.append(code).append("\n"); + } + log.info(LoggerMarker.RELEASE_MARKER, "{}", errorMsg.toString()); - // 写入CSV行,包含页数 - writer.printf("%s,%s,%d%n", /* 逻辑文件名(就是档号)*/ archiveCode, logicalAddress, page); - safeOnPhaseProgress(Phase.GENERATE_LOGICAL, current, totalRecords); + throw new RuntimeException(errorMsg.toString()); + } else { + // 写入CSV头部(包含页数列) + writer.println("逻辑文件名,逻辑地址,页数"); + int totalRecords = records.stream().mapToInt(r -> r.page).sum(); + int current = 0; + + // 处理每条记录 + for (Record record : records) { + String archiveCode = record.archiveCode; + int page = record.page; + + // 生成逻辑地址(不包含页数) + String logicalAddress = generateFileLevelLogicalAddress(archiveCode); + + // 写入CSV行,包含页数 + writer.printf("%s,%s,%d%n", /* 逻辑文件名(就是档号)*/ archiveCode, logicalAddress, page); + safeOnPhaseProgress(Phase.GENERATE_LOGICAL, current, totalRecords); + } } } diff --git a/src/main/java/top/r3944realms/docchecktoolrefactored/core/PhysicalAddressFileGenerator.java b/src/main/java/top/r3944realms/docchecktoolrefactored/core/PhysicalAddressFileGenerator.java index 00e964a..a072e68 100644 --- a/src/main/java/top/r3944realms/docchecktoolrefactored/core/PhysicalAddressFileGenerator.java +++ b/src/main/java/top/r3944realms/docchecktoolrefactored/core/PhysicalAddressFileGenerator.java @@ -3,11 +3,14 @@ package top.r3944realms.docchecktoolrefactored.core; import lombok.extern.slf4j.Slf4j; import org.apache.pdfbox.Loader; import org.apache.pdfbox.pdmodel.PDDocument; +import org.ofdrw.reader.OFDReader; import top.r3944realms.docchecktoolrefactored.util.LoggerMarker; import java.io.File; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; @Slf4j public class PhysicalAddressFileGenerator implements AddressFileGenerator { @@ -55,10 +58,8 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { try (PrintWriter writer = new PrintWriter(outputFile, StandardCharsets.UTF_8)) { if (folderType == PAGE_TYPE) { - writer.println("物理文件名,物理地址"); processPageLevelFolder(rootFolder, writer, outputFile.getAbsolutePath(), callback, counter, totalFiles); } else if (folderType == FILE_TYPE) { - writer.println("物理文件名,物理地址,页数"); processFileLevelFolder(rootFolder, writer, outputFile.getAbsolutePath(), callback, counter, totalFiles); } else { throw new IllegalArgumentException("不支持的文件夹类型: " + folderType); @@ -66,7 +67,17 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { } safeOnPhaseCompleted(Phase.GENERATE_PHYSICAL); - } catch (Exception e) { + } catch (RuntimeException e) { + // 直接重新抛出自定义的重复文件名异常,不让它被日志吞掉 + if (e.getMessage() != null && e.getMessage().startsWith("存在重复文件名:")) { + throw e; + } + safeOnPhaseCompleted(Phase.GENERATE_PHYSICAL); + safeOnPhaseProgress(Phase.GENERATE_PHYSICAL, 0, 0); + log.error("生成物理地址文件失败: {}", e.getMessage(), e); + throw e; // 重新抛出异常,确保能被上层捕获 + } + catch (Exception e) { safeOnPhaseCompleted(Phase.GENERATE_PHYSICAL); safeOnPhaseProgress(Phase.GENERATE_PHYSICAL, 0, 0); log.error("生成物理地址文件失败: {}", e.getMessage(), e); @@ -90,6 +101,7 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { } return count; } + /** * 处理页面级文件夹及其内部文件 * @@ -98,6 +110,61 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { * @param outputFilePath 输出文件的绝对路径 */ private void processPageLevelFolder(File folder, PrintWriter writer, String outputFilePath, ProgressCallback callback, int[] counter, int total) { + Set seenFileNames = new HashSet<>(); + Set duplicateFileNames = new HashSet<>(); + + // 收集所有重复的文件名 + collectPageLevelFileNames(folder, outputFilePath, seenFileNames, duplicateFileNames); + + // 如果存在重复文件名,记录日志并抛出异常 + if (!duplicateFileNames.isEmpty()) { + StringBuilder errorMsg = new StringBuilder("存在重复文件名:\n"); + for (String name : duplicateFileNames) { + errorMsg.append(name).append("\n"); + } + log.info(LoggerMarker.RELEASE_MARKER, "{}", errorMsg.toString()); + throw new RuntimeException(errorMsg.toString()); + } else { + // 写入CSV头部 + writer.println("物理文件名,物理地址"); + + // 处理文件(与原来的方法类似,但排除了重复检查) + processPageLevelFolderInternal(folder, writer, outputFilePath, callback, counter, total); + } + } + + /** + * 递归收集页面级文件夹中的所有文件名以检测重复 + */ + private void collectPageLevelFileNames(File folder, String outputFilePath, + Set seenFileNames, Set duplicateFileNames) { + File[] filesAndFolders = folder.listFiles(file -> !file.isHidden()); + + if (filesAndFolders != null) { + for (File file : filesAndFolders) { + // 跳过输出文件本身 + if (file.getAbsolutePath().equals(outputFilePath)) continue; + + if (file.isFile() && isImageFile(file.getName())) { + // 移除文件扩展名 + String fileName = file.getName().substring(0, file.getName().lastIndexOf('.')); + // 检查是否重复 + if (!seenFileNames.add(fileName)) { + duplicateFileNames.add(fileName); + } + } else if (file.isDirectory()) { + // 递归处理子文件夹 + collectPageLevelFileNames(file, outputFilePath, seenFileNames, duplicateFileNames); + } + } + } + } + + /** + * 实际处理页面级文件夹的内部实现(无重复检查) + */ + private void processPageLevelFolderInternal(File folder, PrintWriter writer, String outputFilePath, + ProgressCallback callback, int[] counter, int total) { // 获取该文件夹下的所有非隐藏文件和文件夹 File[] filesAndFolders = folder.listFiles(file -> !file.isHidden()); @@ -108,7 +175,6 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { // 只处理图片文件,跳过其他类型的文件 if (file.isFile() && isImageFile(file.getName())) { - // 移除文件扩展名 String fileNameWithoutExt = file.getName().substring(0, file.getName().lastIndexOf('.')); @@ -125,12 +191,22 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { safeOnPhaseProgress(Phase.GENERATE_PHYSICAL, counter[0], total); } else if (file.isDirectory()) { // 递归处理子文件夹 - processPageLevelFolder(file, writer, outputFilePath, callback, counter, total); + processPageLevelFolderInternal(file, writer, outputFilePath, callback, counter, total); } } } } + + + + + + + + + + /** * 处理文件级文件夹(处理PDF文件) * @@ -139,6 +215,60 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { * @param outputFilePath 输出文件的绝对路径 */ private void processFileLevelFolder(File folder, PrintWriter writer, String outputFilePath, ProgressCallback callback, int[] counter, int total) { + Set seenFileNames = new HashSet<>(); + Set duplicateFileNames = new HashSet<>(); + + // 收集所有重复的文件名 + collectFileLevelFileNames(folder, outputFilePath, seenFileNames, duplicateFileNames); + + // 如果存在重复文件名,记录日志并抛出异常 + if (!duplicateFileNames.isEmpty()) { + StringBuilder errorMsg = new StringBuilder("存在重复文件名:\n"); + for (String name : duplicateFileNames) { + errorMsg.append(name).append("\n"); + } + log.info(LoggerMarker.RELEASE_MARKER, "{}", errorMsg.toString()); + throw new RuntimeException(errorMsg.toString()); + } else { + // 写入CSV头部 + writer.println("物理文件名,物理地址,页数"); + + // 处理文件(与原来的方法类似,但排除了重复检查) + processFileLevelFolderInternal(folder, writer, outputFilePath, callback, counter, total); + } + } + + /** + * 递归收集文件级文件夹中的所有文件名以检测重复 + */ + private void collectFileLevelFileNames(File folder, String outputFilePath, + Set seenFileNames, Set duplicateFileNames) { + File[] filesAndFolders = folder.listFiles(file -> !file.isHidden()); + + if (filesAndFolders != null) { + for (File file : filesAndFolders) { + // 跳过输出文件本身 + if (file.getAbsolutePath().equals(outputFilePath)) continue; + + if (file.isFile() && isPdfFile(file.getName())) { + String fileName = file.getName().substring(0, file.getName().lastIndexOf('.')); + // 检查是否重复 + if (!seenFileNames.add(fileName)) { + duplicateFileNames.add(fileName); + } + } else if (file.isDirectory()) { + // 递归处理子文件夹 + collectFileLevelFileNames(file, outputFilePath, seenFileNames, duplicateFileNames); + } + } + } + } + + /** + * 实际处理文件级文件夹的内部实现(无重复检查) + */ + private void processFileLevelFolderInternal(File folder, PrintWriter writer, String outputFilePath, + ProgressCallback callback, int[] counter, int total) { // 获取该文件夹下的所有非隐藏文件和文件夹 File[] filesAndFolders = folder.listFiles(file -> !file.isHidden()); @@ -149,47 +279,57 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { continue; } - if (file.isFile()&& isPdfFile(file.getName())) { - // 移除文件扩展名 - String fileNameWithoutExt = file.getName().substring(0, file.getName().lastIndexOf('.')); + if (file.isFile() && isPdfFile(file.getName())) { + // 移除文件扩展名 + String fileNameWithoutExt = file.getName().substring(0, file.getName().lastIndexOf('.')); - // 生成物理地址路径(使用与页面级相同的逻辑) - String physicalAddress = generatePhysicalAddress(file.getAbsolutePath(), fileNameWithoutExt); + // 生成物理地址路径(使用与页面级相同的逻辑) + String physicalAddress = generatePhysicalAddress(file.getAbsolutePath(), fileNameWithoutExt); - // 获取PDF页数 - int pageCount = getPdfPageCount(file); + // 获取PDF页数 + int pageCount = getPdfPageCount(file); - // 写入CSV行 - writer.printf("%s,%s,%d%n", fileNameWithoutExt, physicalAddress, pageCount); + // 写入CSV行 + writer.printf("%s,%s,%d%n", fileNameWithoutExt, physicalAddress, pageCount); - counter[0]++; - safeOnPhaseProgress(Phase.GENERATE_PHYSICAL, counter[0], total); + counter[0]++; + safeOnPhaseProgress(Phase.GENERATE_PHYSICAL, counter[0], total); } else if (file.isDirectory()) { // 递归处理子文件夹 - processFileLevelFolder(file, writer, outputFilePath, callback, counter, total); + processFileLevelFolderInternal(file, writer, outputFilePath, callback, counter, total); } } } } - /** - * 获取PDF文件的页数 - * - * @param pdfFile PDF文件 - * @return 页数 - */ - private int getPdfPageCount(File pdfFile) { - // 使用Apache PDFBox库获取PDF页数 - try (PDDocument document = Loader.loadPDF(pdfFile)){ - int pageCount = document.getNumberOfPages(); - document.close(); - return pageCount; - } catch (Exception e) { - log.warn(LoggerMarker.RELEASE_MARKER, "无法获取PDF文件页数: {}", pdfFile.getAbsolutePath(), e); - return 0; +/** + * 获取PDF或OFD文件的页数 + * + * @param file 文件 + * @return 页数 + */ +private int getPdfPageCount(File file) { + try { + if (file.getName().toLowerCase().endsWith(".pdf")) { + // 使用Apache PDFBox库获取PDF页数 + try (PDDocument document = Loader.loadPDF(file)) { + int pageCount = document.getNumberOfPages(); + return pageCount; + } + } else if (file.getName().toLowerCase().endsWith(".ofd")) { + // 使用OFDRW库获取OFD页数 + try (org.ofdrw.reader.OFDReader reader = new org.ofdrw.reader.OFDReader(file.toPath())) { + // 获取OFD文档的页面数量 + int pageCount = reader.getNumberOfPages(); + return pageCount; + } } + } catch (Exception e) { + log.warn(LoggerMarker.RELEASE_MARKER, "无法获取文件页数: {}", file.getAbsolutePath(), e); + return 0; } - + return 0; +} /** * 判断是否为PDF文件 @@ -198,7 +338,7 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { * @return 是否为PDF文件 */ private boolean isPdfFile(String fileName) { - return fileName.toLowerCase().endsWith(".pdf"); + return fileName.toLowerCase().endsWith(".pdf")|| fileName.toLowerCase().endsWith(".ofd"); } /** @@ -211,7 +351,8 @@ public class PhysicalAddressFileGenerator implements AddressFileGenerator { String lowerFileName = fileName.toLowerCase(); return lowerFileName.endsWith(".jpg") || lowerFileName.endsWith(".jpeg") || lowerFileName.endsWith(".png") || lowerFileName.endsWith(".bmp") || - lowerFileName.endsWith(".gif") || lowerFileName.endsWith(".tiff"); + lowerFileName.endsWith(".gif") || lowerFileName.endsWith(".tiff")|| + lowerFileName.endsWith(".jp2"); // 支持 JPEG 2000 格式 } /** diff --git a/src/main/java/top/r3944realms/docchecktoolrefactored/ui/module/PathCheckPaneController.java b/src/main/java/top/r3944realms/docchecktoolrefactored/ui/module/PathCheckPaneController.java index 50d1167..ef55b84 100644 --- a/src/main/java/top/r3944realms/docchecktoolrefactored/ui/module/PathCheckPaneController.java +++ b/src/main/java/top/r3944realms/docchecktoolrefactored/ui/module/PathCheckPaneController.java @@ -179,7 +179,7 @@ public class PathCheckPaneController implements Initializable { // 当任务完成时显示完整结果 task.setOnSucceeded(e -> { progressBar.closeProgress(); - result2TA.setText(task.getValue()); + result2TA.setText("生成逻辑路径 csv 文件任务完成,输出csv文件路径:"+task.getValue()); generateLogicalAddress2B.setDisable(false); addResultSuccessfulStyle(); log.info(LoggerMarker.RELEASE_MARKER, "生成逻辑路径 csv 文件任务完成,输出csv文件路径:{}", task.getValue()); @@ -296,7 +296,7 @@ public class PathCheckPaneController implements Initializable { // 当任务完成时显示完整结果 task.setOnSucceeded(e -> { progressBar.closeProgress(); - result2TA.setText(task.getValue()); + result2TA.setText("生成物理路径 csv 文件任务完成,输出csv文件路径:"+task.getValue()); generatePhysicalAddress2B.setDisable(false); log.info(LoggerMarker.RELEASE_MARKER, "生成物理路径 csv 文件任务完成,输出csv文件路径:{}", task.getValue()); addResultSuccessfulStyle(); diff --git a/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/AddressFileGenerationTask.java b/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/AddressFileGenerationTask.java index e4f8117..5af1b00 100644 --- a/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/AddressFileGenerationTask.java +++ b/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/AddressFileGenerationTask.java @@ -75,6 +75,13 @@ public class AddressFileGenerationTask extends Task { if (e instanceof RuntimeException && e.getMessage() != null && e.getMessage().startsWith("存在重复档号:")) { + outputFile.delete(); // 删除空内容的csv文件 + throw e; // 直接抛出,保留原始消息 + } + if (e instanceof RuntimeException && + e.getMessage() != null && + e.getMessage().startsWith("存在重复文件名:")) { + outputFile.delete();// 删除空内容的csv文件 throw e; // 直接抛出,保留原始消息 } throw new RuntimeException("地址文件生成失败", e); diff --git a/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/DuplicateDocumentDetectionTask.java b/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/DuplicateDocumentDetectionTask.java index b1e9917..9ddf017 100644 --- a/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/DuplicateDocumentDetectionTask.java +++ b/src/main/java/top/r3944realms/docchecktoolrefactored/ui/task/DuplicateDocumentDetectionTask.java @@ -25,6 +25,7 @@ public class DuplicateDocumentDetectionTask extends Task{ private final String folderPath; private final DuplicateFinder duplicateFinder; + public DuplicateDocumentDetectionTask(String folderPath) { this.folderPath = folderPath; // 创建带进度更新的扫描器 @@ -48,6 +49,7 @@ public class DuplicateDocumentDetectionTask extends Task{ // 用于统计文件总数 AtomicInteger totalFiles = new AtomicInteger(0); + // 使用 RobustParallelScanner 和 MD5HashCalculator 进行并行扫描和哈希计算 // 设置进度回调 duplicateFinder.setProgressCallback(new DuplicateFinder.ProgressCallback() { @@ -127,50 +129,59 @@ public class DuplicateDocumentDetectionTask extends Task{ List duplicateGroups = resultRef.get(); // 构建最终结果 - return generateResult(duplicateGroups, totalFiles); + return generateResult(duplicateGroups, totalFiles, + duplicateFinder.getTargetFilesCount(), + duplicateFinder.getOtherFilesCount()); } - private static @NotNull String generateResult(List duplicateGroups, AtomicInteger totalFiles) { - StringBuilder result = new StringBuilder(); + // Update method signature +private static @NotNull String generateResult(List duplicateGroups, + AtomicInteger totalFiles, + int targetFilesCount, + int otherFilesCount) { + StringBuilder result = new StringBuilder(); + // Calculate total duplicate files + int totalDuplicateFiles = duplicateGroups.stream() + .mapToInt(group -> group.fileMetas().size()) + .sum(); - // 计算总文件数(所有组中的文件数) - int totalDuplicateFiles = duplicateGroups.stream() - .mapToInt(group -> group.fileMetas().size()) - .sum(); + int totalGroups = duplicateGroups.size(); - int totalGroups = duplicateGroups.size(); + result.append(String.format("总共扫描文件数: %d\n", totalFiles.get())); + result.append(String.format("其中目标文件(jpg jpeg png bmg gif tiff jp2 pdf ofd )数: %d\t", targetFilesCount)); + result.append(String.format(" 非目标文件数: %d\n", otherFilesCount)); + result.append(String.format("发现重复文件组数: %d\n", totalGroups)); + result.append(String.format("重复文件总数: %d\n", totalDuplicateFiles)); - result.append(String.format("总共扫描文件数: %d\n", totalFiles.get())); - result.append(String.format("发现重复文件组数: %d\n", totalGroups)); - result.append(String.format("重复文件总数: %d\n", totalDuplicateFiles)); + // Rest of the existing implementation remains the same + if (!duplicateGroups.isEmpty()) { + result.append("\n详细重复文件信息:\n"); + result.append("----------------------------------------\n"); - if (!duplicateGroups.isEmpty()) { - result.append("\n详细重复文件信息:\n"); - result.append("----------------------------------------\n"); + int groupIndex = 1; + for (DuplicateGroup group : duplicateGroups) { + result.append(String.format("第 %d 组 (哈希值: %s, 大小: %d 字节)\n", + groupIndex, group.hash(), group.size())); - int groupIndex = 1; - for (DuplicateGroup group : duplicateGroups) { - result.append(String.format("第 %d 组 (哈希值: %s, 大小: %d 字节)\n", - groupIndex, group.hash(), group.size())); - - int fileIndex = 1; - for (var file : group.fileMetas()) { - Path filePath = file.getPath(); - result.append(String.format(" 文件%d: %s\n", fileIndex, filePath.toAbsolutePath())); - fileIndex++; - } - result.append("\n"); - groupIndex++; + int fileIndex = 1; + for (var file : group.fileMetas()) { + Path filePath = file.getPath(); + result.append(String.format(" 文件%d: %s\n", fileIndex, filePath.toAbsolutePath())); + fileIndex++; } - } else { - result.append("\n没有发现重复文件\n"); + result.append("\n"); + groupIndex++; } - - result.append("检测完成!\n"); - return result.toString(); + } else { + result.append("\n没有发现重复文件\n"); } + result.append("检测完成!\n"); + return result.toString(); +} + + @Override protected void cancelled() { super.cancelled(); @@ -178,4 +189,5 @@ public class DuplicateDocumentDetectionTask extends Task{ duplicateFinder.shutdown(); updateMessage("操作已被取消"); } + }