文本夹比对工具
2025-07-02 20:55 l_v_y_forever 阅读(17) 评论(0) 收藏 举报
比对两个文件夹是否一致的工具类,具体实现如下:
1 package com.whb; 2 3 import java.io.BufferedInputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.nio.file.Files; 7 import java.nio.file.Path; 8 import java.nio.file.Paths; 9 import java.util.ArrayList; 10 import java.util.Arrays; 11 import java.util.HashMap; 12 import java.util.HashSet; 13 import java.util.List; 14 import java.util.Map; 15 import java.util.Set; 16 import java.util.stream.Collectors; 17 import java.util.stream.Stream; 18 19 public class FolderComparator { 20 21 public static class FolderDiff { 22 private final List<Path> missingInFirst = new ArrayList<>(); 23 private final List<Path> missingInSecond = new ArrayList<>(); 24 private final List<Path> sizeMismatch = new ArrayList<>(); 25 private final List<Path> contentMismatch = new ArrayList<>(); 26 private final Map<Path, Long> sizeDetails = new HashMap<>(); 27 private int totalFilesCompared; 28 private int identicalFiles; 29 30 public void addMissingInFirst(Path path) { 31 missingInFirst.add(path); 32 } 33 34 public void addMissingInSecond(Path path) { 35 missingInSecond.add(path); 36 } 37 38 public void addSizeMismatch(Path path) { 39 sizeMismatch.add(path); 40 } 41 42 public void addContentMismatch(Path path) { 43 contentMismatch.add(path); 44 } 45 46 public void recordSize(Path path, long size) { 47 sizeDetails.put(path, size); 48 } 49 50 public void incrementTotal() { 51 totalFilesCompared++; 52 } 53 54 public void incrementIdentical() { 55 identicalFiles++; 56 } 57 58 public boolean isIdentical() { 59 return missingInFirst.isEmpty() && 60 missingInSecond.isEmpty() && 61 sizeMismatch.isEmpty() && 62 contentMismatch.isEmpty(); 63 } 64 65 public void printReport() { 66 System.out.println("\n===== 文件夹比对报告 ====="); 67 System.out.println("总文件数: " + totalFilesCompared); 68 System.out.println("一致文件数: " + identicalFiles); 69 System.out.println("差异文件数: " + 70 (totalFilesCompared - identicalFiles)); 71 72 if (isIdentical()) { 73 System.out.println("\n两个文件夹内容完全一致"); 74 return; 75 } 76 77 printSection("第一个文件夹中缺失的文件", missingInFirst); 78 printSection("第二个文件夹中缺失的文件", missingInSecond); 79 printSection("文件大小不一致的文件", sizeMismatch); 80 printSection("文件内容不一致的文件", contentMismatch); 81 82 // 打印详细大小差异 83 if (!sizeMismatch.isEmpty()) { 84 System.out.println("\n文件大小差异详情:"); 85 for (Path path : sizeMismatch) { 86 Long size1 = sizeDetails.get(path); 87 Long size2 = sizeDetails.get(path.resolve("__second__")); 88 System.out.printf(" %s: %d bytes vs %d bytes\n", 89 path, size1, size2); 90 } 91 } 92 } 93 94 private void printSection(String title, List<Path> paths) { 95 if (!paths.isEmpty()) { 96 System.out.println("\n" + title + " (" + paths.size() + "):"); 97 for (Path path : paths) { 98 System.out.println(" " + path); 99 } 100 } 101 } 102 } 103 104 public static FolderDiff compareFolders(Path firstFolder, Path secondFolder) throws IOException { 105 if (!Files.isDirectory(firstFolder)) { 106 throw new IllegalArgumentException(firstFolder + " 不是文件夹"); 107 } 108 if (!Files.isDirectory(secondFolder)) { 109 throw new IllegalArgumentException(secondFolder + " 不是文件夹"); 110 } 111 112 FolderDiff diff = new FolderDiff(); 113 114 // 获取所有文件的相对路径 115 Set<Path> firstFiles = listFilesRecursively(firstFolder); 116 Set<Path> secondFiles = listFilesRecursively(secondFolder); 117 118 // 找出缺失的文件 119 for (Path path : firstFiles) { 120 if (!secondFiles.contains(path)) { 121 diff.addMissingInSecond(path); 122 } 123 } 124 for (Path path : secondFiles) { 125 if (!firstFiles.contains(path)) { 126 diff.addMissingInFirst(path); 127 } 128 } 129 130 // 比较共同文件 131 Set<Path> commonFiles = new HashSet<>(firstFiles); 132 commonFiles.retainAll(secondFiles); 133 134 for (Path relativePath : commonFiles) { 135 diff.incrementTotal(); 136 Path firstFile = firstFolder.resolve(relativePath); 137 Path secondFile = secondFolder.resolve(relativePath); 138 139 // 比较文件大小 140 long firstSize = Files.size(firstFile); 141 long secondSize = Files.size(secondFile); 142 diff.recordSize(relativePath, firstSize); 143 diff.recordSize(relativePath.resolve("__second__"), secondSize); 144 145 if (firstSize != secondSize) { 146 diff.addSizeMismatch(relativePath); 147 continue; 148 } 149 150 // 大小相同的情况下比较内容 151 if (compareFileContent(firstFile, secondFile)) { 152 diff.incrementIdentical(); 153 } else { 154 diff.addContentMismatch(relativePath); 155 } 156 } 157 158 return diff; 159 } 160 161 private static Set<Path> listFilesRecursively(Path folder) throws IOException { 162 try (Stream<Path> paths = Files.walk(folder)) { 163 return paths.filter(Files::isRegularFile) 164 .map(folder::relativize) 165 .collect(Collectors.toSet()); 166 } 167 } 168 169 private static boolean compareFileContent(Path firstFile, Path secondFile) { 170 try { 171 long size = Files.size(firstFile); 172 173 // 小文件使用单次读取比较 174 if (size <= 8192) { 175 byte[] firstBytes = Files.readAllBytes(firstFile); 176 byte[] secondBytes = Files.readAllBytes(secondFile); 177 return Arrays.equals(firstBytes, secondBytes); 178 } 179 180 // 大文件使用缓冲比较 181 try (InputStream is1 = new BufferedInputStream(Files.newInputStream(firstFile)); 182 InputStream is2 = new BufferedInputStream(Files.newInputStream(secondFile))) { 183 184 byte[] buffer1 = new byte[8192]; 185 byte[] buffer2 = new byte[8192]; 186 187 int bytesRead1; 188 while ((bytesRead1 = is1.read(buffer1)) != -1) { 189 int bytesRead2 = is2.read(buffer2, 0, bytesRead1); 190 if (bytesRead2 != bytesRead1) { 191 return false; 192 } 193 for (int i = 0; i < bytesRead1; i++) { 194 if (buffer1[i] != buffer2[i]) { 195 return false; 196 } 197 } 198 } 199 200 // 检查第二个文件是否还有剩余内容 201 return is2.read() == -1; 202 } 203 } catch (IOException e) { 204 System.err.println("比较文件内容时出错: " + e.getMessage()); 205 return false; 206 } 207 } 208 209 public static void main(String[] args) { 210 // if (args.length != 2) { 211 // System.out.println("用法: java FolderComparator <第一个文件夹路径> <第二个文件夹路径>"); 212 // System.out.println("示例: java FolderComparator C:/folder1 D:/folder2"); 213 // return; 214 // } 215 216 String firstFolderPath = "/Users/whbt/dir1"; 217 String secondFolderPath = "/Users/whb/dir2"; 218 Path firstFolder = Paths.get(firstFolderPath); 219 Path secondFolder = Paths.get(secondFolderPath); 220 221 222 try { 223 System.out.println("开始比对文件夹..."); 224 System.out.println("文件夹1: " + firstFolder.toAbsolutePath()); 225 System.out.println("文件夹2: " + secondFolder.toAbsolutePath()); 226 227 long startTime = System.currentTimeMillis(); 228 FolderDiff diff = compareFolders(firstFolder, secondFolder); 229 long duration = System.currentTimeMillis() - startTime; 230 231 diff.printReport(); 232 233 System.out.printf("\n比对完成! 耗时: %.2f 秒%n", duration / 1000.0); 234 } catch (IOException e) { 235 System.err.println("比对过程中出错: " + e.getMessage()); 236 e.printStackTrace(); 237 } 238 } 239 } 240
浙公网安备 33010602011771号