java文件对比
这个其实写的是有点问题的,想的是一个线程读 多个线程对比,结果写的是一个线程读一个线程对比
总归是个写的思路
controller
package com.taiyusoft.tydms.controller;
import com.alibaba.fastjson.JSONObject;
import com.taiyusoft.tydms.entity.ResponseForm;
import com.taiyusoft.tydms.service.FileComparesService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
/***
* @Author
* @Param
* @return
**/
@RestController
@RequestMapping("/fileComparesimple")
public class FileCompareController {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private FileComparesService fileComparesService;
@RequestMapping("/selectfileComparesimple")
public void fileComparesimple(String firstpath, String secondpath) {
long time1 = System.currentTimeMillis();
File file = new File(firstpath);
if (file.isFile() || file.isDirectory()) {
JSONObject list = fileComparesService.fileComparesimple(firstpath, secondpath);
}
long time2 = System.currentTimeMillis();
int time = (int) ((time2 - time1) / 1000);
System.out.println("执行了:" + time + "秒!");
}
/**
* 进度条初始化 直接调用文件对比
*
* @return
*/
@RequestMapping("/fileComparesinit")
public ResponseForm fileComparesinit(String firstpath, String secondpath) {
ResponseForm responseForm = new ResponseForm();
Integer sum = 0;
try {
sum = fileComparesService.initPercentage(firstpath, secondpath);
if (sum != 0) {
File file1 = new File(firstpath);
File file2 = new File(secondpath);
if (file1.isFile() || file1.isDirectory() && file2.isFile() || file2.isDirectory()) {
JSONObject list = fileComparesService.fileComparesimple(firstpath, secondpath);
responseForm.setData(list);
responseForm.setCode("200");
responseForm.setMessage(ResponseForm.message.SUCCESS);
}
}
} catch (Exception e) {
e.printStackTrace();
responseForm.setCode("400");
responseForm.setMessage(ResponseForm.message.FAIL);
}
return responseForm;
}
/**
* 文件对比时间过长时,出现该当前文件进度条百分比
*/
@RequestMapping("/fileComparesimplePercentage")
public ResponseForm fileComparesimplePercentage() {
ResponseForm responseForm = new ResponseForm();
JSONObject jsonObject;
try {
jsonObject = fileComparesService.fileComparesimplePercentage();
responseForm.setData(jsonObject);
responseForm.setCode("200");
responseForm.setMessage(ResponseForm.message.SUCCESS);
} catch (Exception e) {
responseForm.setCode("400");
responseForm.setMessage(ResponseForm.message.FAIL);
}
return responseForm;
}
/**
* 文件处理时间过长时,专门获取文件对比结果
*
* @return
*/
@RequestMapping("/getfileCompares")
public ResponseForm getfileCompares() {
ResponseForm responseForm = new ResponseForm();
JSONObject jsonObject;
try {
jsonObject = fileComparesService.getfileCompares();
responseForm.setData(jsonObject);
responseForm.setCode("200");
responseForm.setMessage(ResponseForm.message.SUCCESS);
} catch (Exception e) {
responseForm.setCode("400");
responseForm.setMessage(ResponseForm.message.FAIL);
}
return responseForm;
}
}
Service
package com.taiyusoft.tydms.service;
import com.alibaba.fastjson.JSONObject;
public interface FileComparesService {
JSONObject fileComparesimple(String firstpath, String secondpath);
Integer initPercentage(String firstpath, String secondpath);
JSONObject fileComparesimplePercentage();
JSONObject getfileCompares();
}
Serviceimpl
package com.taiyusoft.tydms.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.taiyusoft.tydms.base.util.CompareThreadUtil;
import com.taiyusoft.tydms.base.util.ReadFile2;
import com.taiyusoft.tydms.entity.Fc;
import com.taiyusoft.tydms.service.FileComparesService;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Service
public class FileComparesServiceImpl implements FileComparesService {
private static final Logger logger = Logger.getLogger(FileComparesServiceImpl.class);
public static String syncCurrentName1 = null; // 进度条name
public static String percentage1 ; // 进度条百分比
public static Integer percentagesum1 = null; // 文件总数
public static int countfile;//当前文件个数
public static final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();//全局静态变量
private List listoneNot1 = new ArrayList<Fc>(); //存放数据一缺失的数据
private List listoneNot2 = new ArrayList<Fc>(); //存放数据二缺失的数据
private List listoneNot3 = new ArrayList<Fc>(); //存放数据二缺失的数据
public static boolean flag;
private Boolean[] scanStop = new Boolean[1]; // 检测停止标识
@Override
public JSONObject fileComparesimple(String firstpath, String secondpath) {
long startTime = System.currentTimeMillis();
int cpuCount = 4;
// String dirName1 = "C:\\Users\\taiyu\\Desktop\\file2\\10w";
String dirName1 = firstpath;
File root1 = new File(dirName1);
String dirName2 = secondpath;
File root2 = new File(dirName2);
listoneNot1 = new ArrayList<Fc>();
listoneNot2 = new ArrayList<Fc>();
listoneNot3 = new ArrayList<Fc>();
scanStop[0] = true;
List list = new ArrayList();
list.add(dirName1);
list.add(dirName2);
logger.info("分配线程开始...");
CountDownLatch latchs = new CountDownLatch(cpuCount + 1);
ExecutorService exec = Executors.newCachedThreadPool();
// 读取文件线程
final ReadFile2 trFile1 = new ReadFile2(
latchs, null, list,
dirName1, dirName2,scanStop);
logger.info("读取文件线程启动...");
exec.execute(new Thread() {
@Override
public void run() {
trFile1.readFile();
}
});
final CompareThreadUtil thDao = new CompareThreadUtil(
latchs, null, list, listoneNot1,
listoneNot2, listoneNot3, root1,
root2, dirName1, dirName2, trFile1,scanStop);
for (int i = 0; i < cpuCount; i++) {
System.out.println("检测线程" + i + " 启动...");
final int currentID = i;
exec.execute(new Thread() {
@Override
public void run() {
thDao.addFileLevelAfter(currentID,percentagesum1,countfile);
}
});
}
try {
exec.shutdown();
latchs.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//结束时间
long endTime1 = System.currentTimeMillis();
//打印
System.out.println("对比运行时间:" + (double) (endTime1 - startTime) / 1000 + "s");
//打印数据1缺失数据
if (listoneNot1.size() > 0) {
logger.info("数据1删除的文件如下");
for (int i = 0; i < listoneNot1.size(); i++) {
logger.info(((Fc) listoneNot1.get(0)).getPath());
}
} else {
logger.info("数据1无删除的文件...");
}
//打印数据2缺失数据
if (listoneNot2.size() > 0) {
logger.info("数据2删除的文件如下");
for (int i = 0; i < listoneNot2.size(); i++) {
logger.info(((Fc) listoneNot2.get(i)).getPath());
}
} else {
logger.info("数据2无删除文件");
}
//打印数据3缺失数据
if (listoneNot3.size() > 0) {
logger.info("两数据源之间发生修改的文件如下");
for (int i = 0; i < listoneNot3.size(); i++) {
logger.info(((Fc) listoneNot3.get(i)).getPath());
}
} else {
logger.info("两数据源之间无发生修改的文件");
}
//结束时间
long endTime = System.currentTimeMillis();
//打印
System.out.println("程序运行时间:" + (double) (endTime - startTime) / 1000 + "s");
JSONObject jsonObject = new JSONObject();
jsonObject.put("数据源1发生删除的文件",listoneNot1);
jsonObject.put("数据源2发生删除的文件",listoneNot2);
jsonObject.put("两数据源对比发生修改的文件",listoneNot3);
flag=true;
jsonObject.put("flag",flag);
return jsonObject;
}
@Override
public Integer initPercentage(String firstpath, String secondpath) {
flag=false;
percentagesum1=0;
percentage1="";
syncCurrentName1="";
readFileInfo(new File(firstpath));
readFileInfo(new File(secondpath));
return percentagesum1;
}
@Override
public JSONObject fileComparesimplePercentage() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("百分比",percentage1);
jsonObject.put("当前进行到的文件",syncCurrentName1);
jsonObject.put("flag",flag);//为true时可以取结果
return jsonObject;
}
@Override
public JSONObject getfileCompares() {
JSONObject jsonObject = new JSONObject();
jsonObject.put("数据源1发生删除的文件",listoneNot1);
jsonObject.put("数据源2发生删除的文件",listoneNot2);
jsonObject.put("两数据源对比发生修改的文件",listoneNot3);
return jsonObject;
}
private void readFileInfo(File root) {
if (root.exists()) {
if (root.isDirectory()) {
File[] files = root.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
percentagesum1++;
} else if (files[i].isDirectory()) {
readFileInfo(files[i]);
}
files[i] = null;
}
}
files = null;
} else if (root.isFile()) {
percentagesum1++;
}
}
}
}
读取文件多线程工具类
package com.taiyusoft.tydms.base.util;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReadFile2 {
// private static final Logger logger = Logger.getLogger(ReadFile.class);
private CountDownLatch latch;
private CyclicBarrier barrier;
private LinkedList<File> linkedList = new LinkedList();//总
private Lock lock = new ReentrantLock();
private Object numberLock = new Object();
private boolean lockboo = false;
private List<String> list;
private File root1;
private File root2;
private String dirName1;
private String dirName2;
private Boolean[] StopIt;
public ReadFile2(CountDownLatch latch, CyclicBarrier barrier,
List list,
String dirName1, String dirName2,
Boolean[] stop
) {
this.latch = latch;
this.barrier = barrier;
this.list = list;
this.dirName1 = dirName1;
this.dirName2 = dirName2;
this.StopIt = stop;
}
// 读取文件信息
public void readFile() {
try {
readFileInfo(new File(list.get(0)));
readFileInfo(new File(list.get(1)));
// logger.info("读取文件线程正常停止!");
System.out.println("读取文件线程正常停止!");
} catch (Exception e) {
System.out.println("错误信息!" + e);
} finally {
StopIt[0] = false;
latch.countDown();
}
}
private void readFileInfo(File root) {
if (root.exists()) {
if (root.isDirectory()) {
File[] files = root.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {
addFile(files[i]);
} else if (files[i].isDirectory()) {
readFileInfo(files[i]);
}
files[i] = null;
}
}
files = null;
} else if (root.isFile()) {
addFile(root);
}
}
}
private void addFile(File file) {
lock.lock();
try {
linkedList.addLast(file);
} catch (Exception e) {
System.out.println("添加文件出错:" + e);
} finally {
lock.unlock();
// try {
// if (linkedList.size() >= 10000) {
// synchronized (numberLock) {
// lockboo = true;
// numberLock.wait();
// }
// }
// } catch (Exception e2) {
logger.error("锁出错:", e2);
// System.out.println("锁出错" + e2);
// }
}
}
public void getFileInfo(File[] file) {
lock.lock();
try {
file[0] = linkedList.pollFirst();
if (lockboo && linkedList.size() <= 1000) {
synchronized (numberLock) {
lockboo = false;
numberLock.notify();
}
}
} catch (Exception e) {
// logger.error("获取文件出错:", e);
System.out.println("获取文件出错:" + e);
} finally {
lock.unlock();
}
}
}
对比文件多线程工具类
package com.taiyusoft.tydms.base.util;
import com.taiyusoft.tydms.entity.Fc;
import com.taiyusoft.tydms.service.impl.FileComparesServiceImpl;
import java.io.File;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CompareThreadUtil {
private CountDownLatch latch;
private CyclicBarrier barrier;
private LinkedList linkedList = new LinkedList();//总
private LinkedList<Fc> linkedList1 = new LinkedList<Fc>();//读取路径1中的所有的文件
private LinkedList<Fc> linkedList2 = new LinkedList<Fc>();//读取路径2中的所有的文件
private Lock lock = new ReentrantLock();
private List listoneNot1 = new ArrayList<Fc>(); //存放数据一缺失的数据
private List listoneNot2 = new ArrayList<Fc>(); //存放数据二缺失的数据
private List listoneNot3 = new ArrayList<Fc>(); //存放数据二缺失的数据
private Object numberLock = new Object();
private boolean lockboo = false;
private List<String> list;
private File root1;
private File root2;
private String dirName1;
private String dirName2;
private ReadFile2 trFile1;
private Boolean[] StopIt;
public CompareThreadUtil(CountDownLatch latch, CyclicBarrier barrier,
List list,
List<Fc> listoneNot1, List<Fc> listoneNot2,
List<Fc> listoneNot3, File root1, File root2,
String dirName1, String dirName2, ReadFile2 trFile1, Boolean[] stop
) {
this.latch = latch;
this.barrier = barrier;
this.list = list;
this.listoneNot1 = listoneNot1;
this.listoneNot2 = listoneNot2;
this.listoneNot3 = listoneNot3;
this.root1 = root1;
this.root2 = root2;
this.dirName1 = dirName1;
this.dirName2 = dirName2;
this.trFile1 = trFile1;
this.StopIt = stop;
}
public void addFileLevelAfter(int currentID, Integer percentagesum1, int i) {
File[] file = new File[1];
File f0File = null;
lock.lock();
try {
while (true) {
trFile1.getFileInfo(file);
f0File = file[0];
if (!StopIt[0] && f0File == null) {
System.out.println("线程" + currentID + " 突然停止!");
break;
}
if (f0File != null) {
i++;
NumberFormat numberFormat = NumberFormat.getNumberInstance();
numberFormat.setMaximumFractionDigits(2);
String result = numberFormat.format((float) i / (float) percentagesum1 * 100);
FileComparesServiceImpl.percentage1 = result + "%";
FileComparesServiceImpl.syncCurrentName1 = f0File.getName();
System.out.println("当前为检测线程" + currentID + "读取的文件为第" + i + "个文件" + "文件名为" + f0File + " 文件总数为" + percentagesum1);
System.out.println("此时百分比为" + FileComparesServiceImpl.percentage1);
if (String.valueOf(f0File).startsWith(dirName1)) {
File file1 = new File(f0File.toString().replace(dirName1, dirName2));
if (file1.exists()) {
if (f0File.lastModified() != file1.lastModified()) {
Fc fc1 = new Fc();
fc1.setPath(f0File.getPath());
fc1.setLastmodified(String.valueOf(f0File.lastModified()));
fc1.setMd5(Md5.getMD5File(f0File));
listoneNot3.add(fc1);
}
} else {
Fc fc = new Fc();
fc.setPath(f0File.getPath());
fc.setLastmodified(String.valueOf(f0File.lastModified()));
fc.setMd5(Md5.getMD5File(f0File));
listoneNot1.add(fc);
}
} else {
File file2 = new File(f0File.toString().replace(dirName2, dirName1));
if (file2.exists()) {
if (f0File.lastModified() != file2.lastModified()) {
Fc fc1 = new Fc();
fc1.setPath(f0File.getPath());
fc1.setLastmodified(String.valueOf(f0File.lastModified()));
fc1.setMd5(Md5.getMD5File(f0File));
listoneNot3.add(fc1);
}
} else {
Fc fc = new Fc();
fc.setPath(f0File.getPath());
fc.setLastmodified(String.valueOf(f0File.lastModified()));
fc.setMd5(Md5.getMD5File(f0File));
listoneNot2.add(fc);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("线程" + currentID + " 正常停止!");
} finally {
lock.unlock();
latch.countDown();
}
}
}
控制台结果
检测线程应该是对比到某个文件(不过无伤大雅)
返回结果
进度条结果
个人总结
文件对比这个功能,我大概写了半个多月,
步骤大概就是
0.先沟通需求,看能不能降低需求难度(很重要)(比如文件对比这个最先的想法是做出类似于idea的文件对比,但是idea的文件对比是什么数量级,你要的什么数量级你不清楚吗?)
1.先有写的思路,无论这个思路是问别人的还是自己想的还是自己在某个博客里看的,重要的是有实现的思路。
2.写demo,思路试一下行不行得通。
3.优化思路,基本上就是,上多线程,调整多线程。
4.看一下功能运行的时间 是否满意 ,不满意重新1,2,3(从看文件比对这个专栏,也可以看出,我大概写了5-6个不同的解决思路,最初的方案是直接比对md5值 1k文件比对直接上100s,最后的结果是20w文件比对15s(普通笔记本))
5.最后就是,上项目