这里说的改进是相对于第一版https://blog.csdn.net/qq_46037812/article/details/120163996来说的

写这个小工具的目的是方便我在电脑上进行把webdav挂载的云盘中的笔记与本地笔记同步、把平时拍的照片进行多端同步的操作,其实有很多现成的软件可以完美地完成这件事,比如Microsoft SyncToy之类的,不过这是在我做完第一版之后才知道的,所以干脆一不做二不休,再完善一下自己做的小工具,让它更好地胜任我平时需要的文件同步工作。

注意:此工具未经过全面的测试,可能存在一些bug,不建议用在重要文件之上。

对比上个版本,有以下改进

  1. 支持空文件夹的同步、无效文件夹的删除
  2. 另起线程进行费时的查找、同步操作,避免堵塞swing线程
  3. 同步操作有可视化的进度百分比,当同步的文件数量很多或者同步的目标文件夹是在本地挂载的云盘中,导致上传文件受网速限制时,这个进度百分比还是挺有用的。

目前处于学习阶段,代码改得比较乱,可能存在很多不必要的操作影响性能,欢迎大家指出不足之处。


源码

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class File_Syn
{static Map<String, File> fileMap = new HashMap<>();static Map<String, File> folderMap = new HashMap<>();static Map<String, File> fileMap1 = new HashMap<>();static Map<String, File> fileMap2 = new HashMap<>();static Map<String, File> folderMap1 = new HashMap<>();static Map<String, File> folderMap2 = new HashMap<>();static Map<String, File> deleteFileMap = new HashMap<>();static Map<String, File> nullFolder = new HashMap<>();static int count = 0;public static void main(String[] args) { new Form();}/**** @param file 源文件夹* @param fileMap 文件夹中的文件Map* @param sourceFilePath 源文件夹路径* @return Map*/public static Map<String, File> getFileMap(File file, Map<String, File> fileMap, Map<String, File> folderMap,String sourceFilePath){for (int i = 0; i < file.listFiles().length; i++){File childFile = file.listFiles()[i];if (!childFile.isDirectory()) //如果不是文件夹{String childPath = childFile.getAbsolutePath(); //获取绝对路径String relativePath = childPath.substring(sourceFilePath.length());//从绝对路径中取得相对路径fileMap.put(relativePath,childFile);}else{folderMap.put(childFile.getAbsolutePath().substring(sourceFilePath.length()),childFile);  //获取文件夹结构getFileMap(childFile, fileMap, folderMap,sourceFilePath);//递归查询}}return fileMap;}/*** 查询两个文件夹中的差异文件个数,将差异文件路径存储在fileMap中* @param sourceFile 源文件夹* @param destinationFile 目标文件夹*/public static void search(File sourceFile, File destinationFile){fileMap1 = getFileMap(sourceFile, fileMap1, folderMap1,sourceFile.getAbsolutePath());fileMap2 = getFileMap(destinationFile, fileMap2, folderMap2,destinationFile.getAbsolutePath());for (Map.Entry<String, File> entry : fileMap1.entrySet()) //遍历源文件夹的文件{String key = entry.getKey();if (fileMap2.containsKey(key)) //如果目标文件夹中存在此文件{Date date1 = new Date(entry.getValue().lastModified());Date date2 = new Date(fileMap2.get(key).lastModified());if (date1.after(date2)) //对比最后修改时间,如果源文件夹中文件较新,则更新{fileMap.put(key, entry.getValue());}}else{fileMap.put(key, entry.getValue());}}for (Map.Entry<String, File> entry : folderMap1.entrySet())  //遍历文件夹{String key = entry.getKey();if (!folderMap2.containsKey(key)){folderMap.put(key,entry.getValue());}}for (Map.Entry<String, File> entry : fileMap2.entrySet()) //需要删除的差异{String key = entry.getKey();if (!fileMap1.containsKey(key)){deleteFileMap.put(key,entry.getValue());}}for (Map.Entry<String, File> entry : folderMap2.entrySet()) //无效文件夹{String key = entry.getKey();if (!folderMap1.containsKey(key)){nullFolder.put(key,entry.getValue());}}}/**** @param destinationFile 目标文件夹* @param jTextArea 文本域*/public static void change(File destinationFile,JTextArea jTextArea){String destinationFilePath = destinationFile.getAbsolutePath();for (Map.Entry<String, File> entry : folderMap.entrySet())  //建立文件夹结构{String key = entry.getKey();File file = new File(destinationFilePath + key);file.mkdirs();}for (Map.Entry<String, File> entry : fileMap.entrySet())  //同步文件{String key = entry.getKey();File file1 = entry.getValue();File file2 = new File(destinationFilePath + key);if (fileMap2.containsKey(key)){file2 = fileMap2.get(key);file2.delete(); //删除已存在的文件}try {Files.copy(file1.toPath(), file2.toPath()); //文件复制count++;}catch (IOException e) {e.printStackTrace();jTextArea.setText("同步失败");}}for (Map.Entry<String, File> entry : deleteFileMap.entrySet())  //删除无效文件{File deleteFile = entry.getValue();if (deleteFile.exists()){deleteFile.delete();}count++;}for (Map.Entry<String, File> entry : nullFolder.entrySet())  //删除无效文件夹{File deleteFolder = entry.getValue();if (deleteFolder.exists())deleteFolder(deleteFolder);}jTextArea.setText("同步完成");}public static void deleteFolder(File file){File[] files = file.listFiles();if (files.length != 0){for (int i = 0; i < files.length; i++)deleteFolder(files[i]);}file.delete();count++;}public static void clear(){folderMap.clear();fileMap.clear();fileMap1.clear();fileMap2.clear();folderMap1.clear();folderMap2.clear();deleteFileMap.clear();nullFolder.clear();count = 0;}
}
class Form extends JFrame
{Font font = new Font("宋体",0,20);JButton sourceBtn = new JButton("选择源文件夹");JButton destinationBtn = new JButton("选择目标文件夹");JButton compare = new JButton("对比文件夹");JButton change = new JButton("同步");JTextArea jTextArea1 = new JTextArea(2,25);JTextArea jTextArea2 = new JTextArea(2,25);JTextArea result = new JTextArea(3,25);JPanel jPanel1 = new JPanel();JPanel jPanel2 = new JPanel();JPanel jPanel3 = new JPanel();JPanel jPanel4 = new JPanel();JPanel jPanel5 = new JPanel();JFileChooser jFileChooser = new JFileChooser();File sourceFilePath = null;File destinationFilePath = null;Form(){setSize(300,450);setDefaultCloseOperation(EXIT_ON_CLOSE);setLayout(new GridLayout(5,1));setLocationRelativeTo(null);setVisible(true);jTextArea1.setFont(font);jTextArea1.setLineWrap(true);jTextArea1.setWrapStyleWord(true);jTextArea2.setFont(font);jTextArea2.setLineWrap(true);jTextArea2.setWrapStyleWord(true);result.setFont(font);result.setLineWrap(true);result.setWrapStyleWord(true);jPanel1.add(sourceBtn);jPanel1.add(destinationBtn);jPanel2.add(jTextArea1);jPanel3.add(jTextArea2);jPanel4.add(compare);jPanel4.add(change);jPanel5.add(result);add(jPanel1);add(jPanel2);add(jPanel3);add(jPanel4);add(jPanel5);jFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);sourceBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {int returnVal = jFileChooser.showOpenDialog(null);if (returnVal == JFileChooser.APPROVE_OPTION){sourceFilePath = jFileChooser.getSelectedFile();jTextArea1.setText(sourceFilePath.getAbsolutePath());}}});destinationBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {int returnVal = jFileChooser.showOpenDialog(null);if (returnVal == JFileChooser.APPROVE_OPTION){destinationFilePath  = jFileChooser.getSelectedFile();jTextArea2.setText(destinationFilePath.getAbsolutePath());}}});compare.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if (sourceFilePath == null || destinationFilePath == null){result.setText("未选择文件夹");return;}if (sourceFilePath.equals(destinationFilePath)){result.setText("源文件夹和目标文件夹不能相同");return;}File_Syn.clear();result.setText("正在查找差异文件");new Thread(new t1()).start();}});change.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {if (File_Syn.fileMap.isEmpty() && File_Syn.deleteFileMap.isEmpty() && File_Syn.nullFolder.isEmpty()){result.setText("文件差异列表为空");return;}new Thread(new t2_per()).start();new Thread(new t2()).start();}});}class t1 implements Runnable{@Overridepublic void run() {long start = System.currentTimeMillis();File_Syn.search(sourceFilePath,destinationFilePath);long finish = System.currentTimeMillis();result.setText("查找到"+(File_Syn.fileMap.size()+File_Syn.deleteFileMap.size()+File_Syn.nullFolder.size())+"处差异,其中"+File_Syn.nullFolder.size()+"个无效文件夹");if ((finish - start) > 1000)result.append("\n执行耗时:"+(finish-start)/1000+"秒");elseresult.append("\n执行耗时:"+(finish-start)+"毫秒");}}class t2 implements Runnable{@Overridepublic void run() {long start = System.currentTimeMillis();File_Syn.change(destinationFilePath,result);long finish = System.currentTimeMillis();if ((finish - start) > 1000)result.append("\n执行耗时:"+(finish-start)/1000+"秒");elseresult.append("\n执行耗时:"+(finish-start)+"毫秒");}}class t2_per implements Runnable{@Overridepublic void run() {BigDecimal percentage;int all = File_Syn.fileMap.size()+File_Syn.deleteFileMap.size()+File_Syn.nullFolder.size();BigDecimal bigAll = new BigDecimal(all);BigDecimal b100 = new BigDecimal(1);DecimalFormat decimalFormat = new DecimalFormat("0.00%");do {percentage = new BigDecimal(File_Syn.count).divide(bigAll,4, BigDecimal.ROUND_HALF_DOWN);if (percentage.compareTo(b100) == -1)result.setText("正在处理,进度:"+decimalFormat.format(percentage));try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}} while (percentage.compareTo(b100) == -1);if (bigAll.compareTo(new BigDecimal(File_Syn.count)) == 0)File_Syn.clear();elseresult.setText("同步存在异常,未完全完成");}}
}

运行截图

Java实现两个文件夹之间的同步(改进版)相关推荐

  1. 如何实现两个文件夹内容自动同步?

    如何实现两个文件夹内容自动同步?这其实涉及到文件备份的相关知识,两个文件夹内容自动同步,简单里面就是两个文件夹里的文件内容要保持相同,专业一点来说就是双向同步备份. 我想很多小伙伴都想知道这个问题的答 ...

  2. 如何在同一台电脑上保持两个文件夹的内容同步更新?

    很多时候我们因工作需要,想要在同一台电脑上保持两个文件夹的内容文件同步更新,保持一致.那么除了人工手动复制粘贴,还有其他方法吗?今天小西就给大家介绍一款文件同步备份软件,可实现两个文件夹文件自动同步更 ...

  3. java两个文件夹比较路径_比较Java中两个文件的路径

    java两个文件夹比较路径 Given the paths of the two files and we have two compare the paths of the files in Jav ...

  4. Java io流---拷贝文件夹下的所有文件和目录

    Java io流-拷贝文件夹下的所有文件和目录 代码: package demo01;import java.io.*; import java.util.TreeMap;public class C ...

  5. 群晖增量同步Linux文件夹,用自定义脚本实现群晖NAS中本地文件夹之间的增量同步复制...

    用自定义脚本实现群晖NAS中本地文件夹之间的增量同步复制 2021-02-21 15:39:44 60点赞 646收藏 52评论 使用情景:群晖DS918+,两块12T RAID1存重要数据,1块2T ...

  6. 更好地整理数据:windows下怎么让不同路径下的两个文件夹保持同步内容

    目录 1.使用"同步工具"软件 2.使用Robocopy命令 3.Robocopy的一个小例子 4.自动复制 4.1打开任务计划程序 4.2 创建任务 4.3 设置触发器 4.4 ...

  7. Java计算两个字符串日期之间的天数差

    Java计算两个字符串日期之间的天数差 调用方法: public static void main(String[] args) throws ParseException {String a = & ...

  8. Python判断两个文件夹中互相不同的文件有哪些、判断一个文件夹相对于另外一个文件夹缺少了哪些文件

    Python判断两个文件夹中互相不同的文件有哪些.判断一个文件夹相对于另外一个文件夹缺少了哪些文件 目录 Python判断两个文件夹中互相不同的文件有哪些.判断一个文件夹相对于另外一个文件夹缺少了哪些 ...

  9. Java中 实现通过文件夹选择任一图像,从而进行图像卷积操作

    ** Java中 实现通过文件夹选择任一图像,从而进行图像卷积操作 ** 之前的那篇关于图像卷积的博客(Java中实现图像的卷积效果),只是讲了给定一张图片,从而实现图片的卷积操作:而现在,需要去实现 ...

  10. Linux如何显示文件数目的技巧比较两个文件夹是否相同

    文章目录 如何对比文件数目 比较两个文件夹是否相同 查看文件大小并排序文件大小 工作场景,现在我需要对比同事的一个目录下的文件,与我的目录下的文件数量是否相同,如果数量相同的话,文件是否相同. 如何对 ...

最新文章

  1. 【资源】NLP 算法工程师相关的面试题
  2. 禁止解析PHP、限制user_agent、php相关配置
  3. NHibernate 配置文件的处理和使用多数据库的多层架构思路(第二部分)
  4. 获取自定义组件的宽度和高度
  5. CentOS安装Pure-FTPd+MySQL
  6. 免费分享老男孩全栈9期视频,共126天
  7. IBM加入OpenOffice 贡献Lotus Notes程序代码
  8. ASP.NET MVC3 系列教程 - URL友好化的重型武器[路由]
  9. Python使用xpath爬取51job
  10. RootKit检测工具
  11. 最适合写python程序的软件
  12. 【C#】基础篇(3) C#实现串口助手,解决中文乱码
  13. Python 画图 图例添加字体
  14. JSON (JavaScript Object Notation)
  15. 35岁的程序员:第17章,悲欢离合
  16. 哪里有电,哪里就应该有网络 ,华为移动路由Pro评测
  17. 将List集合用字符串,逗号隔开进行拼接
  18. 性能监控工具-JDK性能监控
  19. c++pthread多线程消费者问题
  20. Delphi图像处理 -- 灰色浮雕

热门文章

  1. 俄罗斯方块代码(自写)
  2. C8051单片机在交流变频调速系统中的应用(收集)
  3. vue 中使用菜鸟打印
  4. 信息系统项目管理师(2022年)—— 重点内容:信息化和信息系统(1)
  5. Pentest Wiki Part6 权限维持
  6. 模拟美萍加密狗--Rockey2虚拟狗(一)
  7. 算法设计与分析学习总结
  8. 陈纪修老师《数学分析》 第11章:欧式空间上的极限和连续 笔记
  9. 表达式求值——数据结构严蔚敏C语言版栈数据结构课后练习
  10. 各个版本Word转Pdf时出现有关PDFMaker加载项崩溃或错误的解决方法