Задача
Написать на pure-Java быстрый алгоритм для подсчета контрольной суммы JAR файла (>1G), по-возможности обойтись без сторонних библиотек.
Стандарный способ
Использовать MD5 дайджест для всего содержимого файла.
MessageDigest digest = MessageDigest.getInstance("MD5");<br/>
byte[]buf = new byte[1024];<br/>
int len = 0;<br/>
InputStream stream = new BufferedInputStream(new FileInputStream(new File("/path/to/jar/file")));<br/>
while((len = stream.read(buf)) > 0){<br/>
digest.update(buf, 0, len);<br/>
}<br/>
stream.close();<br/>
byte[] md5sum = digest.digest();<br/>
Но, можно воспользоваться тем фактом что JAR уже содержит CRC для каждого из файла в архиве.
Используем MD5 дайджест только для CRC последовательности.
Финальная версия
import java.io.*;<br/>
import java.math.*;<br/>
import java.security.*;<br/>
import java.util.*;<br/>
import java.util.jar.*;<br/>
<br/>
public class JarFileChecksum {<br/>
private final File jarFile;<br/>
<br/>
public JarFileChecksum(File jarFile) {<br/>
this.jarFile = jarFile;<br/>
}<br/>
<br/>
public String getChecksum() throws Exception{<br/>
MessageDigest digest = MessageDigest.getInstance("MD5");<br/>
JarFile jar = new JarFile(jarFile);<br/>
int crc;<br/>
byte[]buf = new byte[4];<br/>
for(Enumeration<JarEntry> e=jar.entries();e.hasMoreElements();){<br/>
JarEntry entry = e.nextElement();<br/>
// CRC на самом деле integer<br/>
crc = (int)entry.getCrc();<br/>
// split crc to bytes<br/>
buf[0] = (byte)((crc>>24) & 0xFF);<br/>
buf[1] = (byte)((crc>>16) & 0xFF);<br/>
buf[2] = (byte)((crc>>8) & 0xFF);<br/>
buf[3] = (byte)(crc & 0xFF);<br/>
digest.update(buf);<br/>
}<br/>
jar.close();<br/>
byte[] md5sum = digest.digest();<br/>
// превратим в String<br/>
BigInteger bigInt = new BigInteger(1, md5sum);<br/>
return bigInt.toString(16);<br/>
}<br/>
}
Тесты
Для тестирования был выбран JAR файл размером 1.6G, 37000 файлов и 1500 директорий.
Первый способ:140 секунды
Второй способ: 0.5 секунды