Ускорение 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 мс

Другие вопросы по тегам