У меня было такое же требование, и я выбрал «хэш каталога» в качестве хэша MD5 объединенных потоков всех (не-каталогов) файлов в каталоге. Как Крозин упомянул в комментариях к аналогичному вопросу , вы можете использовать SequenceInputStream
, чтобы действовать как поток, объединяющий нагрузку других потоков. Я использую Кодек Apache Commons для алгоритма MD5.
По сути, вы выполняете поиск по дереву каталогов, добавляя FileInputStream
экземпляров к Vector
для файлов, не относящихся к каталогам. Vector
затем имеет удобный метод elements()
для предоставления Enumeration
, который SequenceInputStream
должен пройти через цикл. Для алгоритма MD5 это просто выглядит как один InputStream
.
Суть в том, что вам нужно, чтобы файлы были представлены в одном и том же порядке каждый раз, чтобы хэш был одинаковым с одинаковыми входными данными. Метод listFiles()
в File
не гарантирует порядок, поэтому я сортирую по имени файла.
Я делал это для файлов, контролируемых SVN, и хотел избежать хэширования скрытых файлов SVN, поэтому я установил флаг, чтобы избежать скрытых файлов.
Соответствующий базовый код приведен ниже. (Очевидно, это может быть «закалено».)
import org.apache.commons.codec.digest.DigestUtils;
import java.io.*;
import java.util.*;
public String calcMD5HashForDir(File dirToHash, boolean includeHiddenFiles) {
assert (dirToHash.isDirectory());
Vector<FileInputStream> fileStreams = new Vector<FileInputStream>();
System.out.println("Found files for hashing:");
collectInputStreams(dirToHash, fileStreams, includeHiddenFiles);
SequenceInputStream seqStream =
new SequenceInputStream(fileStreams.elements());
try {
String md5Hash = DigestUtils.md5Hex(seqStream);
seqStream.close();
return md5Hash;
}
catch (IOException e) {
throw new RuntimeException("Error reading files to hash in "
+ dirToHash.getAbsolutePath(), e);
}
}
private void collectInputStreams(File dir,
List<FileInputStream> foundStreams,
boolean includeHiddenFiles) {
File[] fileList = dir.listFiles();
Arrays.sort(fileList, // Need in reproducible order
new Comparator<File>() {
public int compare(File f1, File f2) {
return f1.getName().compareTo(f2.getName());
}
});
for (File f : fileList) {
if (!includeHiddenFiles && f.getName().startsWith(".")) {
// Skip it
}
else if (f.isDirectory()) {
collectInputStreams(f, foundStreams, includeHiddenFiles);
}
else {
try {
System.out.println("\t" + f.getAbsolutePath());
foundStreams.add(new FileInputStream(f));
}
catch (FileNotFoundException e) {
throw new AssertionError(e.getMessage()
+ ": file should never not be found!");
}
}
}
}