2015-10-15 5 views
1

У меня есть две папки, источник и цель, с файлами и возможными подпапками (структура директорий предполагается одинаковой, вложенные папки и файлы могут входить в любую глубину). Мы хотим, чтобы синхронизировать цель так, что для всех файлов:Как односторонняя синхронизация файлов в двух структурах каталогов в 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(), кажется, не имеют 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 (важно): Я благодарю вас, ребята за ответы на все вопросы, но основная проблема остается нерешенной: со ссылкой на другой каталог, то есть вещи, в комментариях. Ответ h22, кажется, находится где-то на футбольном поле, но этого недостаточно, как объясняется в комментарии ниже. Я был бы очень благодарен, если бы кто-нибудь мог объяснить это еще более маленькими словами. Из опыта это именно та проблема, которую может решить кто-то более здравомыслящий java за пять минут, тогда как я проведу две разочаровывающие недели, заново открыв Америку.

+0

Если вы делаете это в окнах, вы можете просто просто вызвать команду 'xcopy', которая может выполнить тяжелую работу за вас. – bvdb

+0

@bvdb rsync отлично работает в Windows (https://www.itefix.net/cwrsync) и Linux, может синхронизироваться через сеть и может минимизировать пропускную способность через xdelta. Однако OP, похоже, хочет использовать java. – tucuxi

+0

Да, но мне интересно, как сильно это должно быть java :) Я имею в виду, может быть, он не знает, что есть такая вещь, как «Runtime.exec ("xcopy/rsync ..."); '. – bvdb

ответ

1

Рекурсивно переходите к исходной папке. Strip корень папки и адрес местоположения цели непосредственно:

String subPath = sourceFile.getAbsolutePath().substring(sourceRoot.length); 
File targetFile = new File(targetRoot + File.separator + subPath); 

if (targetFile.getParentFile().exists()) { 
    targetFile.getParentFile().mkdirs(); 
} 
// copy, etc 

В противном случае могут возникнуть трудности, если целевое местоположение отсутствует необходимый иерархическую структуру папок, которые могут пройти много каталогов в глубину.

+0

Я думаю, что я добираюсь туда, куда вы направляетесь (отрезайте все, что есть перед корнем источника, а затем добавьте результирующий подпуть к тому, что есть, если перед целевым корнем), но я понимаю, что именно это делает и где использовать его в лучшем случае шатко. И что это такое? Должно быть? Он дает «не удается разрешить», если оставить это так, и «не может быть применен()», когда я добавляю скобки после него. – Sargon1

1

Если у вас есть целевой каталог File targetDir и исходный файл File sourceFile в исходном каталоге вы можете проверить наличие соответствующего целевого файла, написав:

File targetFile = new File(targetDir, sourceFile.getName()); 
boolean exists = targetFile.exists(); 
2

Как WERO указывает, вы можете использовать aFile.exists() для см., существует ли данный путь. Вы также должны объединить его с aFile.isFile(), чтобы проверить, является ли путь нормальным файлом (а не, скажем, папкой).

Проверка содержания - это сложнее. Я предлагаю следующее:

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's FileUtils.contentEquals().

Обратите внимание, что оба вышеуказанных кода и contentEquals сравнивают файлы, а не папки. Чтобы сравнить папки, вам нужно будет использовать рекурсию, вызывая sameContents или эквивалент для каждого файла с одинаковым именем, размером одного и того же размера, и ошибки, если не найдено никакого совпадения для определенного пути в источнике или в месте назначения.