我有同样的需求,并选择将“目录哈希”设置为目录中所有非目录文件串联流的MD5哈希。正如crozin在一个类似的问题的评论中提到的那样,您可以使用SequenceInputStream
作为连接其他流的流。我正在使用Apache Commons Codec进行MD5算法。
基本上,您要通过目录树进行递归,将非目录文件的FileInputStream
实例添加到Vector
中。 Vector
然后方便地具有elements()
方法来提供Enumeration
,这是SequenceInputStream
需要循环的方法。对于MD5算法,这只是一个InputStream
。
需要注意的是,您需要按相同的顺序每次呈现文件,以使哈希在具有相同输入的情况下相同。 File
中的listFiles()
方法不保证排序方式,因此我按文件名排序。
我正在针对受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,
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(".")) {
}
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!");
}
}
}
}
org.apache.commons.codec.digest.DigestUtils.md5Hex
方法之一,而不是上面的代码。 - Dónal