编写一个diff工具,用于判断两个目录下所有的改动 --1.0版本

需求说明:

编写一个diff工具,用于判断两个目录下所有的改动

 

详细介绍:

  1. AB两个目录,目录所在位置及层级均不确定
  2. 需要以B为基准找出两个目录中所有有改动的文件(文件或内容增加、修改、删除),将有改动的文件放入第三个目录中,层级结构与原目录相同
  3. 将所有新增与更新信息记录到更新日志文件中
  4. 将删除信息单独记录到删除日志文件中
  5. 每次执行diff工具需要生成一个新的以日期命名目录存放文件

 

使用场景:

本工具用于软件版本升级时找出两个版本间所有修改过的文件,便于增量替换。

 

提示:

  1. 使用CRC判断文件是否改动
  2. 控制台日志记录使用slf4j增删日志可以使用其他方式记录
  3. 部分jar包已提供,如需使用到新的jar包可自行添加
  1 package comcollection.test;
  2 
  3 import java.io.BufferedInputStream;
  4 import java.io.File;
  5 import java.io.FileInputStream;
  6 import java.io.FileOutputStream;
  7 import java.io.IOException;
  8 import java.nio.channels.FileChannel;
  9 import java.text.SimpleDateFormat;
 10 import java.util.ArrayList;
 11 import java.util.Date;
 12 import java.util.HashMap;
 13 import java.util.List;
 14 import java.util.Map;
 15 import java.util.zip.CRC32;
 16 import org.apache.commons.io.FileUtils;
 17 
 18 /**
 19  * @author MJC 2018年4月24日 上午23:53:45
 20  */
 21 public class DiffUtils {
 22 
 23     private static void writeToFile(File file, String content, String charbyte) {
 24         try {
 25             FileUtils.write(file, content + "\n", "UTF-8", true);
 26         } catch (IOException e) {
 27             e.printStackTrace();
 28         }
 29     }
 30 
 31     @SuppressWarnings("resource")
 32     public static void judgeFileChange(String oldUrl, String newUrl, String diffUrl) {
 33 
 34         FileChannel inputChannel = null;
 35         FileChannel outputChannel = null;
 36         HashMap<String, File> filesMap = getFilesUpdateAndAddMap(oldUrl, newUrl);
 37 
 38         // 创建diffUrl对应的根目录
 39         File fileDir = new File(diffUrl);
 40         fileDir.mkdirs();
 41 
 42         Date now = new Date();
 43         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日HH点mm分ss秒");
 44         String nowTime = dateFormat.format(now);
 45         diffUrl = diffUrl + "\\" + nowTime + "\\";
 46         File fileDire = new File(diffUrl);
 47         fileDire.mkdirs();
 48 
 49         // 创建delete.log、updateAndAdd.log日志文件
 50         String deleteLog = diffUrl + "delete.log";
 51         String updateAndAddLog = diffUrl + "updateAndAdd.log";
 52         File deleteLogFile = null;
 53         File updateAndAddLogFile = null;
 54         deleteLogFile = new File(deleteLog);
 55         updateAndAddLogFile = new File(updateAndAddLog);
 56 
 57         // 遍历删除文件、并且将信息写入日志文件
 58         String timeUrl = "-------- Diff时间:" + nowTime + " --------";
 59         writeToFile(deleteLogFile, timeUrl, "UTF-8");
 60         List<String> oldUrlFilePaths = getAllFilePaths(oldUrl);
 61         List<String> newUrlFilePaths = getAllFilePaths(newUrl);
 62         int count = 0;
 63         long start = System.currentTimeMillis(); // 获取开始时间
 64         for (String filePath : oldUrlFilePaths) {
 65             if (!newUrlFilePaths.contains(filePath)) {
 66                 count++;
 67                 writeToFile(deleteLogFile, filePath, "UTF-8");
 68             }
 69         }
 70         long end = System.currentTimeMillis(); // 获取结束时间
 71         String fileCount = "-------- 共删除文件" + count + "--------";
 72         writeToFile(deleteLogFile, fileCount + "\n", "UTF-8");
 73         String endContent = "-------- 运行完毕,耗时:" + (end - start) + "ms";
 74         writeToFile(deleteLogFile, endContent + "\n", "UTF-8");
 75 
 76         // 遍历新增/更改文件、并且将信息写入日志文件
 77         Date now2 = new Date();
 78         SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy年MM月dd日HH点mm分ss秒");
 79         String nowTime2 = dateFormat2.format(now2);
 80         String timeUrl2 = "-------- Diff时间:" + nowTime2 + " --------";
 81         writeToFile(updateAndAddLogFile, timeUrl2, "UTF-8");
 82         HashMap<String, Long> oldUrlMap = getAllFileMap(oldUrl);
 83         HashMap<String, Long> newUrlMap = getAllFileMap(newUrl);
 84 
 85         for (Map.Entry<String, Long> newUrlMapEntry : newUrlMap.entrySet()) {
 86             // 如果元素存在原来的目录下,并且crc相同,就是更新操作
 87             if (oldUrlMap.containsKey(newUrlMapEntry.getKey())) {
 88                 try {
 89                     long oldUrlCrc = oldUrlMap.get(newUrlMapEntry.getKey());
 90                     long newUrlCrc = newUrlMapEntry.getValue();
 91                     if (oldUrlCrc != newUrlCrc) {
 92                         writeToFile(updateAndAddLogFile, "更新:" + newUrlMapEntry.getKey(), "UTF-8");
 93                     }
 94                 } catch (Exception e) {
 95                     e.printStackTrace();
 96                 }
 97 
 98             } else {// 如果元素不存在A目录下,就是新增的元素
 99                 writeToFile(updateAndAddLogFile, "新增:" + newUrlMapEntry.getKey(), "UTF-8");
100             }
101         }
102         /**
103          * 将新增、更新的文件copy到diffUrl目录下
104          */
105         for (Map.Entry<String, File> addAndUpdate : filesMap.entrySet()) {
106             // 创建每个文件对应的目录
107             File file = addAndUpdate.getValue();
108             String filePath = diffUrl + addAndUpdate.getKey();
109             String fileDirs = filePath.replace(file.getName(), "");
110             File creFileDir = new File(fileDirs);
111             creFileDir.mkdirs();
112 
113             try {
114                 inputChannel = new FileInputStream(file).getChannel();
115                 outputChannel = new FileOutputStream(new File(filePath)).getChannel();
116                 outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
117             } catch (Exception e) {
118                 e.printStackTrace();
119             } finally {
120                 try {
121                     inputChannel.close();
122                 } catch (IOException e) {
123                     e.printStackTrace();
124                 }
125                 try {
126                     outputChannel.close();
127                 } catch (IOException e) {
128                     e.printStackTrace();
129                 }
130             }
131         }
132     }
133 
134     /**
135      * 获取新增/更新文件-用于遍历出file文件,以便复制操作引用此方法
136      * 
137      * @param oldUrl
138      * @param newUrl
139      * @return
140      */
141     private static HashMap<String, File> getFilesUpdateAndAddMap(String oldUrl, String newUrl) {
142         HashMap<String, File> oldUrlMap = getAllFileMaps(oldUrl);
143         HashMap<String, File> newUrlMap = getAllFileMaps(newUrl);
144         HashMap<String, File> addAndUpdateMap = new HashMap<String, File>();
145         for (Map.Entry<String, File> newUrlEntry : newUrlMap.entrySet()) {
146             // 如果元素存在A目录下,且crc相同,就是更新
147             if (oldUrlMap.containsKey(newUrlEntry.getKey())) {
148                 try {
149                     long oldFileCrc = getFileCRC(oldUrlMap.get(newUrlEntry.getKey()));
150                     long newFileCrc = getFileCRC(newUrlEntry.getValue());
151                     if (oldFileCrc != newFileCrc) {
152                         addAndUpdateMap.put(newUrlEntry.getKey(), newUrlEntry.getValue());
153                     }
154                 } catch (Exception e) {
155                     e.printStackTrace();
156                 }
157 
158             } else {// 如果元素不存在A目录下,就是新增的元素
159                 addAndUpdateMap.put(newUrlEntry.getKey(), newUrlEntry.getValue());
160             }
161         }
162         return addAndUpdateMap;
163     }
164 
165     /**
166      * 遍历所有文件-- map的value类型为File形式
167      * 
168      * @param path
169      * @return
170      */
171     private static HashMap<String, File> getAllFileMaps(String path) {
172 
173         List<File> allFileList = new ArrayList<File>();
174         HashMap<String, File> resMap = new HashMap<String, File>();
175 
176         allFileList = getAllFile(new File(path), allFileList);
177         for (File file : allFileList) {
178             resMap.put(file.getAbsolutePath().replace(path, ""), file);
179         }
180         return resMap;
181     }
182 
183     /**
184      * 遍历所有文件-- map的value类型为long形式的CRC 该路径去掉url前缀
185      * 
186      * @param path
187      * @return
188      */
189     private static HashMap<String, Long> getAllFileMap(String url) {
190 
191         List<File> allFileList = new ArrayList<File>();
192         HashMap<String, Long> resMap = new HashMap<String, Long>();
193 
194         allFileList = getAllFile(new File(url), allFileList);
195         for (File file : allFileList) {
196             resMap.put(file.getAbsolutePath().replace(url, ""), getFileCRC(file));
197         }
198         return resMap;
199     }
200 
201     /**
202      * 遍历该目录下的所有文件对应的路径(截取 path之后的路径)
203      * 
204      * @param path
205      * @return
206      */
207     private static List<String> getAllFilePaths(String path) {
208 
209         List<File> allFileList = new ArrayList<File>();
210         List<String> allFilePaths = new ArrayList<String>();
211 
212         allFileList = getAllFile(new File(path), allFileList);
213         for (File file : allFileList) {
214             allFilePaths.add(file.getAbsolutePath().replace(path, ""));
215         }
216 
217         return allFilePaths;
218     }
219 
220     /**
221      * 遍历该目录下的所有文件
222      * 
223      * @param file
224      * @param allFileList
225      * @return
226      */
227     private static List<File> getAllFile(File file, List<File> allFileList) {
228         if (file.exists()) {
229             // 如果当前对象是文件夹,递归调用此方法,获取目录下的所有文件
230             if (file.isDirectory()) {
231                 File f[] = file.listFiles();
232                 for (File tempFile : f) {
233                     getAllFile(tempFile, allFileList);
234                 }
235             } else {
236                 // 如果当前对象是个文件,将文件存到list中
237                 allFileList.add(file);
238             }
239         }
240         return allFileList;
241     }
242 
243     /**
244      * 获取文件的CRC
245      * 
246      * @param file
247      * @return
248      * @throws IOException
249      */
250     private static long getFileCRC(File file) {
251         BufferedInputStream bsrc = null;
252         CRC32 crc = new CRC32();
253         try {
254             bsrc = new BufferedInputStream(new FileInputStream(file));
255             byte[] bytes = new byte[1024];
256             int i;
257             while ((i = bsrc.read(bytes)) != -1) {
258                 crc.update(bytes, 0, i);
259             }
260         } catch (Exception e) {
261 
262         } finally {
263             if (bsrc != null) {
264                 try {
265                     bsrc.close();
266                 } catch (IOException e) {
267                     e.printStackTrace();
268                 }
269             }
270         }
271         return crc.getValue();
272     }
273 }
 1 package comcollection.test;
 2 
 3 
 4 import org.junit.Test;
 5 
 6 /**
 7  * @author MJC 2018年4月24日 上午23:53:45
 8  */
 9 public class DiffUtilsTest {
10     private static final String oldUrl = "C:\\Users\\jljd\\Desktop\\diff工具需求说明及示例\\diff工具需求说明及示例\\A";
11     private static final String newUrl = "C:\\Users\\jljd\\Desktop\\diff工具需求说明及示例\\diff工具需求说明及示例\\B";
12     private static final String diffUrl = "C:\\Users\\jljd\\Desktop\\diff工具需求说明及示例\\diff工具需求说明及示例\\change";
13     
14     @Test
15     public void testjudgeFileChange(){
16         DiffUtils7.judgeFileChange(oldUrl, newUrl, diffUrl);
17     }
18 
19 }

 

posted @ 2018-04-25 01:14  代码改变心态  阅读(525)  评论(0编辑  收藏  举报