代码改变世界

文本夹比对工具

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