У меня есть две структуры каталогов и их необходимо синхронизировать, т. Е. Скопировать в целевую папку файлы и папки из исходной папки, которые являются новыми или измененными, и удалять файлы и папки в целевом объекте, которых нет в источнике. Тем не менее, для этого процесса требуется кнопка «Отмена», которая не позволит ей выполнить и отменить все изменения. Я обыскал и нашел этот код, но мое понимание того, как оно работает, в лучшем случае является туманным.Как реализовать синхронизацию стоп-папок и отмену в java?
//$Id: FileHelper.java 15522 2008-11-05 20:06:43Z hardy.ferentschik $
//Revised from hibernate search util
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Utility class for synchronizing files/directories.
*
* @author Emmanuel Bernard
* @author Sanne Grinovero
* @author Hardy Ferentschik
*/
public abstract class FileHelper {
private static final int FAT_PRECISION = 2000;
public static final long DEFAULT_COPY_BUFFER_SIZE = 16 * 1024 * 1024; // 16 MB
public static boolean areInSync(File source, File destination) throws IOException {
if (source.isDirectory()) {
if (!destination.exists()) {
return false;
}
else if (!destination.isDirectory()) {
throw new IOException(
"Source and Destination not of the same type:"
+ source.getCanonicalPath() + " , " + destination.getCanonicalPath()
);
}
String[] sources = source.list();
Set<String> srcNames = new HashSet<String>(Arrays.asList(sources));
String[] dests = destination.list();
// check for files in destination and not in source
for (String fileName : dests) {
if (!srcNames.contains(fileName)) {
return false;
}
}
boolean inSync = true;
for (String fileName : sources) {
File srcFile = new File(source, fileName);
File destFile = new File(destination, fileName);
if (!areInSync(srcFile, destFile)) {
inSync = false;
break;
}
}
return inSync;
}
else {
if (destination.exists() && destination.isFile()) {
long sts = source.lastModified()/FAT_PRECISION;
long dts = destination.lastModified()/FAT_PRECISION;
return sts == dts;
}
else {
return false;
}
}
}
public static void synchronize(File source, File destination, boolean smart) throws IOException {
synchronize(source, destination, smart, DEFAULT_COPY_BUFFER_SIZE);
}
public static void synchronize(File source, File destination, boolean smart, long chunkSize) throws IOException {
if (chunkSize <= 0) {
System.out.println("Chunk size must be positive: using default value.");
chunkSize = DEFAULT_COPY_BUFFER_SIZE;
}
if (source.isDirectory()) {
if (!destination.exists()) {
if (!destination.mkdirs()) {
throw new IOException("Could not create path " + destination);
}
}
else if (!destination.isDirectory()) {
throw new IOException(
"Source and Destination not of the same type:"
+ source.getCanonicalPath() + " , " + destination.getCanonicalPath()
);
}
String[] sources = source.list();
Set<String> srcNames = new HashSet<String>(Arrays.asList(sources));
String[] dests = destination.list();
//delete files not present in source
for (String fileName : dests) {
if (!srcNames.contains(fileName)) {
delete(new File(destination, fileName));
}
}
//copy each file from source
for (String fileName : sources) {
File srcFile = new File(source, fileName);
File destFile = new File(destination, fileName);
synchronize(srcFile, destFile, smart, chunkSize);
}
}
else {
if (destination.exists() && destination.isDirectory()) {
delete(destination);
}
if (destination.exists()) {
long sts = source.lastModified()/FAT_PRECISION;
long dts = destination.lastModified()/FAT_PRECISION;
//do not copy if smart and same timestamp and same length
if (!smart || sts == 0 || sts != dts || source.length() != destination.length()) {
copyFile(source, destination, chunkSize);
}
}
else {
copyFile(source, destination, chunkSize);
}
}
}
private static void copyFile(File srcFile, File destFile, long chunkSize) throws IOException {
FileInputStream is = null;
FileOutputStream os = null;
try {
is = new FileInputStream(srcFile);
FileChannel iChannel = is.getChannel();
os = new FileOutputStream(destFile, false);
FileChannel oChannel = os.getChannel();
long doneBytes = 0L;
long todoBytes = srcFile.length();
while (todoBytes != 0L) {
long iterationBytes = Math.min(todoBytes, chunkSize);
long transferredLength = oChannel.transferFrom(iChannel, doneBytes, iterationBytes);
if (iterationBytes != transferredLength) {
throw new IOException(
"Error during file transfer: expected "
+ iterationBytes + " bytes, only " + transferredLength + " bytes copied."
);
}
doneBytes += transferredLength;
todoBytes -= transferredLength;
}
}
finally {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
}
boolean successTimestampOp = destFile.setLastModified(srcFile.lastModified());
if (!successTimestampOp) {
System.out.println("Could not change timestamp for {}. Index synchronization may be slow. " + destFile);
}
}
public static void delete(File file) {
if (file.isDirectory()) {
for (File subFile : file.listFiles()) {
delete(subFile);
}
}
if (file.exists()) {
if (!file.delete()) {
System.out.println("Could not delete {}" + file);
}
}
}
}
Кодовые функционирует как рекламируется, но я не уверен о том:
Как бы осуществить отмену? Лучшее, что я могу придумать, - это ввести логическую переменную synchronizedCancelled, которая будет установлена в true при нажатии кнопки отмены и синхронизации шнуровки() с проверками, которые не позволят ему выполнить, если false.
Как осуществить откат? Лучшая идея, которую я могу придумать, это копирование с измененных/удаленных/новых файлов где-то в стороне и последующее копирование их обратно в исходное местоположение после их отмены.
ли мои догадки действительно правильные способы сделать это, есть некоторые предостережения для них, что я не в курсе, или необходимо отменить и Откат быть реализован совершенно по-разному в этом случае?