如何在java中单向同步两个目录结构中的文件?
How to one-way synchronize files in two directory structures in java?
我有两个文件夹,源和目标,里面有文件和可能的子文件夹(假定目录结构相同,子文件夹和文件可以进入任何深度)。我们要同步目标,以便所有文件:
Exists in source, but not in target -> new, copy over to target
Exists in target, but not in source -> deleted, delete from the target
Exists in both, but binary unequal -> changed, copy over from source
Exists in both, and is binary equal -> unchanged, leave be
我遇到的一个问题是检查文件是否存在(listFiles() 的 return 值似乎没有定义 contains()),但更大的障碍是引用其他目录结构。例如,在遍历源文件夹并在那里找到文件时,我如何检查目标文件夹是否包含文件 "foo.txt"?这是我目前所拥有的:
public void synchronize(File source, File target) {
//first loop; accounts for every case except deleted
if (source.isDirectory()) {
for (File i : source.listFiles()) {
if (i.isDirectory()) {
synchronize(i, /**i's equivalent subdirectory in target*/);
}
else if (/**i is new*/) {
/**Copy i over to the appropriate target folder*/
}
else if (/**i is different*/) {
/**copy i over from source to target*/
}
else {/**i is identical in both*/
/**leave i in target alone*/
}
}
for (File i : target.listFiles()) {
if (/**i exists in the target but not in source*/) {
/**delete in target*/
}
}
}
}
EDIT(important): 感谢大家的所有回答,但主要问题仍未解决:指的是其他目录,即评论中的内容。 h22 的答案似乎在大概的某个地方,但这还不够,正如下面的评论中所解释的那样。如果有人能用更小的词来解释这一点,我将不胜感激。根据经验,这正是更 java 精明的人可以在五分钟内解决的问题,而我会花两个令人沮丧的星期重新发现美国。
如果你有一个目标目录 File targetDir
和一个源目录中的源文件 File sourceFile
你可以通过写来检查相应的目标文件是否存在:
File targetFile = new File(targetDir, sourceFile.getName());
boolean exists = targetFile.exists();
正如 wero 指出的那样,您可以使用 aFile.exists()
查看给定路径是否存在。您还应该将它与 aFile.isFile()
结合使用以检查路径是否是普通文件(而不是文件夹)。
检查 content-equals 比较棘手。我提出以下建议:
boolean sameContents(File fa, File fb) throws IOException {
Path a = a.toPath();
Path b = b.toPath();
if (Files.size(a) != Files.size(b)) return false;
return Arrays.equals(
Files.readAllBytes(a), Files.readAllBytes(b));
}
但前提是文件很小;否则你可能 运行 内存不足试图一次比较它们(需要使用 Arrays.equals
)。如果那里有大文件,this answer 建议使用 Apache Commons IO 的 FileUtils.contentEquals()
。
注意上面的代码和contentEquals
都只比较文件,不比较文件夹。要比较文件夹,您需要使用递归,对每个同名、相同大小的文件调用 sameContents
或等效方法,如果在源或目标中找不到特定路径名的匹配项,则会出错。
只递归访问源文件夹。剥离文件夹根目录并直接定位目标位置:
String subPath = sourceFile.getAbsolutePath().substring(sourceRoot.length);
File targetFile = new File(targetRoot + File.separator + subPath);
if (targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
// copy, etc
否则,如果目标位置缺少所需的分层文件夹结构,可能会深入许多目录,您可能会遇到困难。
我有两个文件夹,源和目标,里面有文件和可能的子文件夹(假定目录结构相同,子文件夹和文件可以进入任何深度)。我们要同步目标,以便所有文件:
Exists in source, but not in target -> new, copy over to target Exists in target, but not in source -> deleted, delete from the target Exists in both, but binary unequal -> changed, copy over from source Exists in both, and is binary equal -> unchanged, leave be
我遇到的一个问题是检查文件是否存在(listFiles() 的 return 值似乎没有定义 contains()),但更大的障碍是引用其他目录结构。例如,在遍历源文件夹并在那里找到文件时,我如何检查目标文件夹是否包含文件 "foo.txt"?这是我目前所拥有的:
public void synchronize(File source, File target) {
//first loop; accounts for every case except deleted
if (source.isDirectory()) {
for (File i : source.listFiles()) {
if (i.isDirectory()) {
synchronize(i, /**i's equivalent subdirectory in target*/);
}
else if (/**i is new*/) {
/**Copy i over to the appropriate target folder*/
}
else if (/**i is different*/) {
/**copy i over from source to target*/
}
else {/**i is identical in both*/
/**leave i in target alone*/
}
}
for (File i : target.listFiles()) {
if (/**i exists in the target but not in source*/) {
/**delete in target*/
}
}
}
}
EDIT(important): 感谢大家的所有回答,但主要问题仍未解决:指的是其他目录,即评论中的内容。 h22 的答案似乎在大概的某个地方,但这还不够,正如下面的评论中所解释的那样。如果有人能用更小的词来解释这一点,我将不胜感激。根据经验,这正是更 java 精明的人可以在五分钟内解决的问题,而我会花两个令人沮丧的星期重新发现美国。
如果你有一个目标目录 File targetDir
和一个源目录中的源文件 File sourceFile
你可以通过写来检查相应的目标文件是否存在:
File targetFile = new File(targetDir, sourceFile.getName());
boolean exists = targetFile.exists();
正如 wero 指出的那样,您可以使用 aFile.exists()
查看给定路径是否存在。您还应该将它与 aFile.isFile()
结合使用以检查路径是否是普通文件(而不是文件夹)。
检查 content-equals 比较棘手。我提出以下建议:
boolean sameContents(File fa, File fb) throws IOException {
Path a = a.toPath();
Path b = b.toPath();
if (Files.size(a) != Files.size(b)) return false;
return Arrays.equals(
Files.readAllBytes(a), Files.readAllBytes(b));
}
但前提是文件很小;否则你可能 运行 内存不足试图一次比较它们(需要使用 Arrays.equals
)。如果那里有大文件,this answer 建议使用 Apache Commons IO 的 FileUtils.contentEquals()
。
注意上面的代码和contentEquals
都只比较文件,不比较文件夹。要比较文件夹,您需要使用递归,对每个同名、相同大小的文件调用 sameContents
或等效方法,如果在源或目标中找不到特定路径名的匹配项,则会出错。
只递归访问源文件夹。剥离文件夹根目录并直接定位目标位置:
String subPath = sourceFile.getAbsolutePath().substring(sourceRoot.length);
File targetFile = new File(targetRoot + File.separator + subPath);
if (targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
// copy, etc
否则,如果目标位置缺少所需的分层文件夹结构,可能会深入许多目录,您可能会遇到困难。