Java实现两个文件夹之间的增量同步

本文介绍了一个Java方法,用于对比源文件夹和目标文件夹的差异,并仅更新目标文件夹中过时或缺失的文件。通过递归获取文件Map并比较修改时间实现精准同步,适用于文件管理或自动化部署场景。

同步方向:源文件夹--->目标文件夹

改进版:https://blog.csdn.net/qq_46037812/article/details/120183489

思路

1、分别获取两个文件夹的Map<String, File>,fileMap1,fileMap2

2、对比两个Map,将fileMap2相对于fileMap1中缺失的、过时的文件找出来,另存入一个fileMap

3、使用fileMap对目标文件夹进行更新

注意:此同步过程基于文件,若源文件夹中存在空文件夹,则该空文件夹不会进行同步。


获取Map的方法

/**
     *
     * @param file 源文件夹
     * @param fileMap 文件夹中的文件Map
     * @param sourceFilePath 源文件夹路径
     * @return Map
     */
    public static Map<String, File> getFileMap(File file, Map<String, File> fileMap, 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
                getFileMap(childFile, fileMap, sourceFilePath);//递归查询
        }
        return fileMap;
    }

查找差异的方法 

/**
     * 查询两个文件夹中的差异文件个数,将差异文件路径存储在fileMap中
     * @param sourceFile 源文件夹
     * @param destinationFile 目标文件夹
     */
    public static void search(File sourceFile, File destinationFile)
    {
        fileMap1 = getFileMap(sourceFile, fileMap1, sourceFile.getAbsolutePath());
        fileMap2 = getFileMap(destinationFile, fileMap2, 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());
            }
        }
    }

更新的方法

 /**
     *
     * @param destinationFile 目标文件夹
     */
    public static void change(File destinationFile)
    {
        String destinationFilePath = destinationFile.getAbsolutePath();
        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
            {
                file2.getParentFile().mkdirs(); //建立多层文件夹结构
                Files.copy(file1.toPath(), file2.toPath()); //文件复制
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

源码

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.nio.file.Files;
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> fileMap1 = new HashMap<>();
    static Map<String, File> fileMap2 = new HashMap<>();
    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, 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
                getFileMap(childFile, fileMap, sourceFilePath);//递归查询
        }
        return fileMap;
    }

    /**
     * 查询两个文件夹中的差异文件个数,将差异文件路径存储在fileMap中
     * @param sourceFile 源文件夹
     * @param destinationFile 目标文件夹
     */
    public static void search(File sourceFile, File destinationFile)
    {
        fileMap1 = getFileMap(sourceFile, fileMap1, sourceFile.getAbsolutePath());
        fileMap2 = getFileMap(destinationFile, fileMap2, 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());
            }
        }
    }

    /**
     *
     * @param destinationFile 目标文件夹
     * @param jTextArea 文本域
     */
    public static void change(File destinationFile,JTextArea jTextArea)
    {
        String destinationFilePath = destinationFile.getAbsolutePath();
        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
            {
                file2.getParentFile().mkdirs(); //建立多层文件夹结构
                Files.copy(file1.toPath(), file2.toPath()); //文件复制
            }catch (IOException e) {
                e.printStackTrace();
                jTextArea.setText("同步失败");
            }
            jTextArea.setText("同步完成");
        }
    }
}
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,20);
    JTextArea jTextArea2 = new JTextArea(2,20);
    JTextArea result = new JTextArea(2,20);
    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,350);
        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() {
            @Override
            public 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() {
            @Override
            public 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() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (sourceFilePath == null || destinationFilePath == null)
                {
                    result.setText("未选择文件夹");
                    return;
                }
                long start = System.currentTimeMillis();
                File_Syn.search(sourceFilePath,destinationFilePath);
                long finish = System.currentTimeMillis();
                result.setText("查找到"+File_Syn.fileMap.size()+"处差异文件");
                result.append("\n执行耗时:"+(finish-start)+"毫秒");
            }
        });
        change.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (File_Syn.fileMap.isEmpty())
                {
                    result.setText("文件差异列表为空");
                    return;
                }
                long start = System.currentTimeMillis();
                File_Syn.change(destinationFilePath,result);
                long finish = System.currentTimeMillis();
                result.append("\n执行耗时:"+(finish-start)+"毫秒");
                File_Syn.fileMap.clear();
            }
        });
    }
}

运行截图

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值