– 0x00 前言
之前工作的时候,经常会有客户提交BUG或者新增一个功能等需求。于是我就会在我本地修改代码,然后再打包替换客户的项目。比较麻烦的是,每次更新都需要去SVN看看都改了哪些文件,新增了哪些文件,一个一个去找,然后打包,给客户更新,有些时候一不小心就漏了或者搞错了,非常的烦。其实我一直都想做的事情就是,写一个程序,让程序去实现对比新旧两个项目,然后把新的项目多出来的文件或者变更过的文件复制出来,这样就能省去我好多工作,主要是不用人工一个个的去比对。。 太烦了。
– 0x01 思路
1. 首先,我需要比较两个项目。那么怎样才算我需要进行打包给客户更新的文件呢?这有两种情况:
① 新增的文件。
② 修改过的文件。
③ 删除的文件。
2. 接下来肯定是要用到commons-io的包了,需要先去判断是否新的文件夹中的某个文件是否在旧的文件夹中存在,如果不存在,就是新增的;如果存在,那就需要比较两个文件是否一样的了,这里我们用到了MD5,通过计算两个文件的MD5值来实现比较两个文件是否一样。
package net.wechance.incrementalupdatetool;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 计算大文件MD5
* David 2012-10-12
*/
public class CheckMD5 {
static MessageDigest MD5 = null;
static {
try {
MD5 = MessageDigest.getInstance(“MD5”);
} catch (NoSuchAlgorithmException ne) {
ne.printStackTrace();
}
}
/**
* 对一个文件获取md5值
*@return md5串
*/
public static String getMD5(File file) {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
byte[] buffer = new byte[8192];
int length;
while ((length = fileInputStream.read(buffer)) != -1) {
MD5.update(buffer, 0, length);
}
return new String(Hex.encodeHex(MD5.digest()));
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
if (fileInputStream != null)
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 求一个字符串的md5值
*@param target 字符串
*@return md5 value
*/
public static String MD5(String target) {
return DigestUtils.md5Hex(target);
}
}
主方法类
package net.wechance.incrementalupdatetool;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
/**
* 主方法
* Created by William on 2015/7/10.
*/
public class Main {
private static String oldPath = “”; // 旧路径
private static String newPath = “”; // 新路径
private static String outPath = “”; // 输出路径
static {
Properties prop = new Properties();
InputStream in = Object.class.getResourceAsStream(“/config.properties”);
try {
prop.load(in);
oldPath = prop.getProperty(“oldPath”).trim();
newPath = prop.getProperty(“newPath”).trim();
outPath = prop.getProperty(“outPath”).trim();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void checkFile() {
}
public static void main(String[] args) {
System.out.println(“—————————————“);
System.out.println(“===> 程序已启动”);
System.out.println(“===> 正在遍历文件夹 ” + newPath);
// 遍历新文件目录
Iterator iterator = FileUtils.iterateFiles(new File(newPath), null, true);
// 遍历旧文件目录
Iterator iterator1 = FileUtils.iterateFiles(new File(oldPath), null, true);
// 用于接收被删除的目录
List deleteFiles = new ArrayList();
System.out.println(“===> 遍历完成,开始执行分析”);
long startTime = System.currentTimeMillis(); //获取开始时间
try {
// 遍历比较新旧目录
// 1. 如果文件不存在,则说明是新增的文件,复制该文件到输出路径
// 2. 如果MD5值不一样,则文件被修改,复制该文件到输出路径
while (iterator.hasNext()) {
// 新文件路径
String nPathStr = iterator.next().toString();
File newFile = new File(nPathStr);
// 旧文件路径
File oldFile = new File(nPathStr.replace(newPath, oldPath));
//System.out.println(“===> 正在分析 ” + nPathStr);
// 判断文件是否存在
if (!oldFile.exists()) {
File outFile = new File(nPathStr.replace(newPath, outPath));
FileUtils.copyFile(newFile, outFile);
System.out.println(“===> 已找到新增文件 “);
System.out.println(“======> 复制文件 ” + outFile.toString());
System.out.println(“Done.”);
System.out.println();
} else {
// MD5校验
// 如果不相同,则copy到输出路径
String newMD5 = CheckMD5.getMD5(newFile);
String oldMD5 = CheckMD5.getMD5(oldFile);
if (!StringUtils.equals( newMD5, oldMD5 )) {
File outFile = new File(nPathStr.replace(newPath, outPath));
FileUtils.copyFile(newFile, outFile);
System.out.println(“===> 已找到修改文件 “);
System.out.println(“======> 新文件 ” + newFile + ” (MD5: ” + newMD5 + ” )”);
System.out.println(“======> 旧文件 ” + oldFile + ” (MD5: ” + oldMD5 + ” )”);
System.out.println(“======> 复制文件 ” + outFile.toString());
System.out.println(“Done.”);
System.out.println();
}
}
}
// 遍历旧的文件目录
// 主要是用于查找被删除的文件
System.out.println(“===> 已找到删除文件 “);
while (iterator1.hasNext()) {
// 旧文件路径
String oPathStr = iterator1.next().toString();
// 新文件路径
File newFile = new File(oPathStr.replace(oldPath, newPath));
if (!newFile.exists()) {
deleteFiles.add(oPathStr);
System.out.println(“======> 文件路径 ” + oPathStr);
}
}
} catch (Exception e) {
System.err.println(“发生异常!”);
}
long endTime=System.currentTimeMillis(); //获取结束时间
System.out.println();
System.out.println(“分析完成 耗时:” + ((endTime-startTime) / 1000) + “s”);
System.out.println(“输出路径:” + outPath);
System.out.println(“—————————————“);
}
}
config.properties
#旧路径
oldPath=F:\\test\\oldPath
#新路径
newPath=F:\\test\\newPath
#输出路径
outPath=F:\\test\\outPath
– 0x03 总结
最后,对项目进行测试。
旧文件夹
新文件夹
输出文件夹
控制台
好啦。到此就完工啦。凑合用,可以考虑把它做成一个GUI。可以鼠标点点选择两个对比的目录以及输出的目录。