文件差分更新
项目中需要有一个文件差分更新的功能,本来是想着使用一个版本文件,即先遍历每一个文件,然后生成对应的md5码,然后新文件也采用相同的方法,然后拷贝md5码不一致或者新出现的文件,但是发现不是很好实践,不如去遍历每一个文件,然后对比两个文件之间存在差异。但是使用直接遍历,性能比较差,我们可以使用一个相对路径,把新文件和旧文件,然后之间每一个文件的相对路径即可,这样时间复杂度就是O(n)了。
代码
这里我们使用commons-io的文件工具类,主要是使用它的一个遍历和拷贝。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
工具类代码如下:
package cn.stopyc.util;
import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.filefilter.FileFilterUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
/**
* @program: Utils
* @description: 文件工具类
* @author: stop.yc
* @create: 2023-02-28 00:13
**/
public class MyFileUtils {
static class DirectoryDiff extends DirectoryWalker<File> {
private final File baseDirectory;
private final File compareDirectory;
public DirectoryDiff(File baseDirectory, File compareDirectory) {
super(FileFilterUtils.trueFileFilter(), -1);
this.baseDirectory = baseDirectory;
this.compareDirectory = compareDirectory;
}
/**
* DirectoryDiff调用walk遍历文件时处理文件夹的逻辑,没有该文件直接添加
* @param directory :文件夹
* @param depth :目标深度
* @param results :有差异的结果集
* @return :是否成功
* @throws IOException :io异常
*/
@Override
protected boolean handleDirectory(File directory, int depth, Collection<File> results) throws IOException {
// 获取相对路径
String relativePath = getRelativePath(baseDirectory, directory);
// 计算比较目录下的路径
File compareDir = new File(compareDirectory, relativePath);
if (!compareDir.exists()) {
// 目录不存在时直接添加到结果集中
results.add(directory);
}
return true;
}
/**
* DirectoryDiff调用walk遍历文件时处理文件的逻辑,没有文件或者文件内容不一致时添加
* @param file :文件
* @param depth : 深度
* @param results :结果集
* @throws IOException :ioException
*/
@Override
protected void handleFile(File file, int depth, Collection<File> results) throws IOException {
// 获取相对路径
String relativePath = getRelativePath(baseDirectory, file);
// 计算比较目录下的路径
File compareFile = new File(compareDirectory, relativePath);
if (!compareFile.exists() || !org.apache.commons.io.FileUtils.contentEquals(file, compareFile)) {
//if (!compareFile.exists() || !org.apache.commons.io.FileUtils.isFileNewer(file, compareFile)) {
// 文件不存在或者内容不一致时添加到结果集中
results.add(file);
}
}
/**
* 获取差异文件,并对其进行复制到目标文件夹
* @param baseDirectory :基准文件(最新的文件,与旧版本存在差异)
* @param compareDirectory :对比的文件(需要被更新的文件, 获取新文件的差异内容)
*/
protected static void diffDirectoryIn(File baseDirectory, File compareDirectory) {
Collection<File> diffFiles = new ArrayList<>();
DirectoryDiff diff = new DirectoryDiff(baseDirectory, compareDirectory);
try {
//遍历,内部调用handleFile和handleDirectory,把差异文件进行添加
diff.walk(baseDirectory, diffFiles);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("IOException");
}
//存在差异的文件进行复制.
diffFiles.stream()
.filter(File::isFile)
.forEach(diffFile -> {
String relativePath = getRelativePath(baseDirectory, diffFile);
File baseFile = new File(compareDirectory, relativePath);
if (!baseFile.getParentFile().exists()) {
baseFile.getParentFile().mkdirs();
}
if (diffFile.isDirectory()) {
try {
org.apache.commons.io.FileUtils.copyDirectory(diffFile, baseFile);
} catch (IOException e) {
e.printStackTrace();
}
} else {
try {
org.apache.commons.io.FileUtils.copyFile(diffFile, baseFile);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
/**
* 获取相对路径
* @param base :基准文件
* @param file :目标文件
* @return :相对路径
*/
private static String getRelativePath(File base, File file) {
return base.toURI().relativize(file.toURI()).getPath();
}
}
/**
* 文件差分更新
* @param baseDirectoryPath :新文件路径
* @param compareDirectoryPath :旧文件路径
*/
public static void diffDirectory(String baseDirectoryPath, String compareDirectoryPath) {
File baseDirectory = new File(baseDirectoryPath);
File compareDirectory = new File(compareDirectoryPath);
DirectoryDiff.diffDirectoryIn(baseDirectory, compareDirectory);
}
/**
* 文件差分更新
* @param baseDirectory :新文件
* @param compareDirectory :旧文件
*/
public static void diffDirectory(File baseDirectory, File compareDirectory) {
DirectoryDiff.diffDirectoryIn(baseDirectory, compareDirectory);
}
public static void main(String[] args) throws IOException {
File baseDirectory = new File("F:\\QGAssessment2023Spring\\");
File compareDirectory = new File("F:\\QGAssessment2023Spring - 副本\\");
MyFileUtils.diffDirectory("F:\\QGAssessment2023Spring\\", "F:\\QGAssessment2023Spring - 副本\\");
MyFileUtils.diffDirectory(baseDirectory, compareDirectory);
}
}