Ускорение MD5 проверок массива файлов
Я перебираю массив файлов, чтобы посмотреть, совпадает ли какой-либо из файлов в нем с последним файлом в этом массиве:
List<File> files = Arrays.asList(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).listFiles());
byte[] md5Downloaded = null;
try {
md5Downloaded = createChecksum(files.get(files.size()-1).getAbsolutePath());
} catch (Exception e1) {
e1.printStackTrace();
}
for(File file : files){
try {
byte[] md5CurrentFile = createChecksum(file.getAbsolutePath());
if(Arrays.equals(md5Downloaded, md5CurrentFile) && counter != files.size()-1 ){
alertUserMD5(file, files.get(files.size()-1));
return;
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Вот метод createChecksum, который заимствован:
private static byte[] createChecksum(String filename) throws Exception {
InputStream fis = new FileInputStream(filename);
byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance("MD5");
int numRead;
do {
numRead = fis.read(buffer);
if (numRead > 0) {
complete.update(buffer, 0, numRead);
}
} while (numRead != -1);
fis.close();
return complete.digest();
}
Однако меня не устраивает количество времени, которое занимает этот процесс (около 15 секунд). Я понимаю, что то, что я делаю, сильно зависит от количества файлов в списке, а также от размера этих файлов, но есть ли способ ускорить это?
2 ответа
Похоже, вы пытаетесь выяснить, доступен ли определенный файл. Если файлы, как правило, не связаны, вы можете вычислить md5 только из первых 1024 байтов и сравнить с последним файлом. Если он отличается, нет необходимости сравнивать контрольные суммы целых файлов. Только если они оказываются равными, вам нужно сравнить md5 целых файлов.
Почти забыл: сравнивайте размеры файлов даже раньше, это может привести к досрочному завершению в большинстве случаев - если файлы в основном не связаны.
private void searchFile() {
long t = System.currentTimeMillis();
List<File> files = new ArrayList<File>(Arrays.asList(dir.listFiles()));
File downloaded = files.get(files.size() - 1);
files.remove(files.size()-1);
byte[] md5Downloaded = null;
try {
md5Downloaded = createChecksum(downloaded.getAbsolutePath());
} catch (Exception e1) {
e1.printStackTrace();
}
Collections.sort(files, new Comparator<File>() {
@Override
public int compare(File lhs, File rhs) {
return Long.valueOf(lhs.length()).compareTo(rhs.length());
}
});
final byte[] MD5 = md5Downloaded;
final int position = Collections.binarySearch(files, downloaded, new Comparator<File>() {
@Override
public int compare(File lhs, File rhs) {
int compare = Long.valueOf(lhs.length()).compareTo(rhs.length());
if (compare == 0) {
try {
if (Arrays.equals(MD5, createChecksum(lhs.getAbsolutePath()))) {
return 0;
}
} catch (Exception ignored) {
}
return -1;
} else
return compare;
}
});
if (position >= 0) {
alertUserMD5(files.get(position), downloaded);
}
}
Извините за неработающий пример, сделал это "на бумаге". Вот рабочий пример. Протестировал его в каталоге с 578 файлами = 154 мс