Каков самый быстрый алгоритм хэширования, чтобы проверить, равны ли два файла?

Каков самый быстрый способ создания хеш-функции, которая будет использоваться для проверки того, являются ли два файла равными?

Безопасность не очень важна.

Изменить: я отправляю файл по сетевому соединению и буду уверен, что файл с обеих сторон равен

Ответ 1

Один подход может заключаться в использовании простого алгоритма CRC-32, и только если значения CRC сравниваются равными, повторите хеш с SHA1 или чем-то более надежным. Быстрый CRC-32 будет превосходить криптографически безопасный хеш в любой день.

Ответ 2

Если вы используете очень сложный и/или медленный хеш, загрузка данных с диска займет гораздо больше времени, чем вычисление хэша (если вы не используете RAM-диски или топовые SSD-диски).

Итак, чтобы сравнить два файла, используйте этот алгоритм:

  • Сравнить размеры
  • Сравните даты (будьте осторожны: это может дать вам неправильный ответ, вы должны проверить, действительно ли это относится к вам или нет)
  • Сравнить хеши

Это позволяет быстро сбой (если размеры разные, вы знаете, что файлы разные).

Чтобы сделать вещи еще быстрее, вы можете вычислить хэш один раз и сохранить его вместе с файлом. Также сохраните дату и размер файла в этом дополнительном файле, чтобы вы быстро узнали, когда вам нужно перекомпилировать хэш или удалить хэш файл при изменении основного файла.

Ответ 3

xxhash заявляет о себе как о быстром и сильном конфликте:

http://cyan4973.github.io/xxHash/

Существует 64-разрядный вариант, который работает "еще быстрее" на 64-битных процессорах, чем 32, в целом, хотя и медленнее на 32-разрядных процессорах (go figure).

http://code.google.com/p/crcutil также считается довольно быстрым (и использует аппаратные CRC-инструкции там, где они есть, которые, вероятно, очень быстрые, но если у вас нет оборудования, которое их поддерживает, настолько быстро). Не знаю, хорош ли CRC32c хэш (с точки зрения коллизий) как xxHash или нет...

https://code.google.com/p/cityhash/ кажется похожим и связанным с crcutil [в том, что он может скомпилировать, чтобы использовать аппаратные команды CRC32c, если указано).

Если вы "просто хотите самую быструю скорость сырой скорости" и не заботитесь о качестве случайного распределения хэш-вывода (например, с небольшими наборами или где скорость имеет первостепенное значение), есть несколько быстрых алгоритмов, упомянутых здесь: http ://www.sanmayce.com/Fastest_Hash/ (эти "не вполне случайные" алгоритмы типа распределения в некоторых случаях "достаточно хороши" и очень быстрые). По-видимому, FNV1A_Jesteress является самым быстрым для "длинных" строк, а некоторые - для небольших строк. http://locklessinc.com/articles/fast_hash/ также кажется связанным. Я не исследовал, чтобы увидеть, каковы свойства столкновения.

Ответ 4

Вы можете попробовать MurmurHash, который был специально разработан для быстрой работы и довольно прост в кодировании. Вы можете захотеть и второй, более безопасный хеш, если MurmurHash вернет матч, хотя, чтобы быть уверенным.

Ответ 5

Для этого типа приложений Adler32, вероятно, является самым быстрым алгоритмом с разумным уровнем безопасности. Для больших файлов вы можете рассчитать несколько значений хэша, например, один на блок из 5 Мб файла, что уменьшает вероятность ошибок (например, когда хэши одинаковы, но содержимое файла отличается). Кроме того, эта настройка нескольких хэш-значений может позволить вычисление хеша быть реализована многопоточным способом.

Изменить: (После замечания Стивена Судата)
Предупреждение, если файлы малы!
Криптографические свойства Adler32 или, скорее, его недостатки хорошо известны, в частности, для коротких сообщений. По этой причине предлагаемое решение следует избегать для файлов размером менее нескольких килобайт.
Тем не менее, в этом вопросе, OP явно ищет быстрый алгоритм и отказывается от проблем с безопасностью. Кроме того, стремление к скорости может быть правдоподобно подразумевает, что человек имеет дело с "большими" файлами, а не с маленькими. В этом контексте Adler32, возможно, применяемый параллельно для фрагментов файлов, например 5Mb, остается очень верным ответом. Alder32 известен своей простотой и скоростью. Кроме того, его надежность, оставаясь ниже, чем у CRC одинаковой длины, вполне приемлема для сообщений более 4000 байт.

Ответ 6

Если это только один раз, то при условии, что вам нужно будет прочитать оба файла, чтобы создать хэш обоих из них, почему бы просто не читать через небольшое количество каждого за раз и сравнивать?

В противном случае CRC - очень простой алгоритм.

Ответ 7

То, что мы оптимизируем здесь, - это время, потраченное на выполнение задачи. К сожалению, мы не знаем достаточно о задаче, чтобы узнать, какое оптимальное решение должно быть.

Это для одноразового сравнения двух произвольных файлов? Затем сравните размер, и после этого просто сравните файлы, байт by byte (или mb на mb), если это лучше для вашего IO.

Если это для двух больших наборов файлов или множества наборов файлов, и это не одноразовая работа. но что-то, что будет происходить часто, тогда нужно хранить хэши для каждого файла. Хэш никогда не является уникальным, но хэш с числом слов 9 цифр (32 бита) был бы хорош для около 4 миллиардов комбинаций, а 64-битное число было бы достаточно хорошим, чтобы различать некоторые 16 * 10 ^ 18 Quintillion разных файлов.

Достойный компромисс должен состоять в том, чтобы генерировать 2 32-битных хэша для каждого файла, один для первых 8k, другой для 1MB + 8k, шлепать их вместе как одно 64-битное число. Каталогизация всех существующих файлов в БД должна быть довольно быстрой, и поиск файла-кандидата против этой БД также должен быть очень быстрым. Когда есть совпадение, единственный способ определить, являются ли они одинаковыми, - это сравнить все файлы.

Я верю в то, что даю людям то, что им нужно, что не всегда не то, что они считают нужным, или то, что нужно.

Ответ 8

Почему вы хотите хешировать его?

Если вы хотите удостовериться, что два файла равны, то по определению вам нужно будет прочитать весь файл (если только они не являются буквально одним и тем же файлом, и в этом случае вы можете сказать, просмотрев метаданные в файловой системе). В любом случае, нет причин для хэша, просто прочитайте их и посмотрите, совпадают ли они. Хеширование сделает его менее эффективным. И даже если хеши совпадают, вы все еще не уверены, действительно ли файлы равны.

Изменить: этот ответ был опубликован до того, как вопрос задал вопрос о сети. Он просто спросил о сравнении двух файлов. Теперь, когда я знаю, что между файлами существует сетевой перекос, я бы сказал, просто использую хеш MD5 и делаю с ним.

Ответ 9

В любом случае вы должны полностью прочитать каждый файл (за исключением случаев, когда размеры не совпадают), поэтому просто прочитайте оба файла и сравните блок-блок.

Использование хэша просто увеличивает использование ЦП и не более того. Поскольку вы ничего не пишете, кеш ОС будет эффективно DROP данных, которые вы читаете, поэтому в Linux просто используйте cmp tool

Ответ 10

Ниже приведен код для поиска дубликатов файлов из моего личного проекта для сортировки изображений, которые также удаляют дубликаты. Согласно моему опыту, сначала использование быстрого хэширования algo, как CRC32, а затем выполнение MD5 или SHA1 было еще медленнее и не улучшилось, так как большинство файлов с одинаковыми размерами действительно дублировались, поэтому работающий хеширование дважды был более дорогим с точки зрения процессора, этот подход может быть неправильным для всех типов проектов, но это определенно верно для файлов изображений. Здесь я делаю хеширование MD5 или SHA1 только в файлах с одинаковым размером.

PS: зависит от кодека Apache commons для эффективного генерации хэша.

Использование образца: новый DuplicateFileFinder ( "MD5" ). findDuplicateFilesList (filesList);

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;

    import org.apache.commons.codec.digest.DigestUtils;

    /**
     * Finds the duplicate files using md5/sha1 hashing, which is used only for the sizes which are of same size.
     *  
     * @author HemantSingh
     *
     */
    public class DuplicateFileFinder {

        private HashProvider hashProvider;
        // Used only for logging purpose.
        private String hashingAlgo;

        public DuplicateFileFinder(String hashingAlgo) {
            this.hashingAlgo = hashingAlgo;
            if ("SHA1".equalsIgnoreCase(hashingAlgo)) {
                hashProvider = new Sha1HashProvider();
            } else if ("MD5".equalsIgnoreCase(hashingAlgo)) {
                hashProvider = new Md5HashProvider();
            } else {
                throw new RuntimeException("Unsupported hashing algorithm:" + hashingAlgo + " Please use either SHA1 or MD5.");
            }
        }

        /**
         * This API returns the list of duplicate files reference.
         * 
         * @param files
         *            - List of all the files which we need to check for duplicates.
         * @return It returns the list which contains list of duplicate files for
         *         e.g. if a file a.JPG have 3 copies then first element in the list
         *         will be list with three references of File reference.
         */
        public List<List<File>> findDuplicateFilesList(List<File> files) {
            // First create the map for the file size and file reference in the array list.
            Map<Long, List<File>> fileSizeMap = new HashMap<Long, List<File>>();
            List<Long> potDuplicateFilesSize = new ArrayList<Long>();

            for (Iterator<File> iterator = files.iterator(); iterator.hasNext();) {
                File file = (File) iterator.next();
                Long fileLength = new Long(file.length());
                List<File> filesOfSameLength = fileSizeMap.get(fileLength);
                if (filesOfSameLength == null) {
                    filesOfSameLength = new ArrayList<File>();
                    fileSizeMap.put(fileLength, filesOfSameLength);
                } else {
                    potDuplicateFilesSize.add(fileLength);
                }
                filesOfSameLength.add(file);
            }

            // If we don't have any potential duplicates then skip further processing.
            if (potDuplicateFilesSize.size() == 0) {
                return null;
            }

            System.out.println(potDuplicateFilesSize.size() + " files will go thru " + hashingAlgo + " hash check to verify if they are duplicate.");

            // Now we will scan the potential duplicate files, and eliminate false positives using md5 hash check.
            List<List<File>> finalListOfDuplicates = new ArrayList<List<File>>();
            for (Iterator<Long> potDuplicatesFileSizeIterator = potDuplicateFilesSize
                    .iterator(); potDuplicatesFileSizeIterator.hasNext();) {
                Long fileSize = (Long) potDuplicatesFileSizeIterator.next();
                List<File> potDupFiles = fileSizeMap.get(fileSize);
                Map<String, List<File>> trueDuplicateFiles = new HashMap<String, List<File>>();
                for (Iterator<File> potDuplicateFilesIterator = potDupFiles.iterator(); potDuplicateFilesIterator
                        .hasNext();) {
                    File file = (File) potDuplicateFilesIterator.next();
                    try {
                        String md5Hex = hashProvider.getHashHex(file);
                        List<File> listOfDuplicatesOfAFile = trueDuplicateFiles.get(md5Hex);
                        if (listOfDuplicatesOfAFile == null) {
                            listOfDuplicatesOfAFile = new ArrayList<File>();
                            trueDuplicateFiles.put(md5Hex, listOfDuplicatesOfAFile);
                        }
                        listOfDuplicatesOfAFile.add(file);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                Collection<List<File>> dupsOfSameSizeList = trueDuplicateFiles.values();
                for (Iterator<List<File>> dupsOfSameSizeListIterator = dupsOfSameSizeList.iterator(); dupsOfSameSizeListIterator
                        .hasNext();) {
                    List<File> list = (List<File>) dupsOfSameSizeListIterator.next();
                    // It will be duplicate only if we have more then one copy of it.
                    if (list.size() > 1) {
                        finalListOfDuplicates.add(list);
                        System.out.println("Duplicate sets found: " + finalListOfDuplicates.size());
                    }
                }
            }

            return finalListOfDuplicates;
        }

        abstract class HashProvider {
            abstract String getHashHex(File file) throws IOException ;
        }

        class Md5HashProvider extends HashProvider {
            String getHashHex(File file) throws IOException {
                return DigestUtils.md5Hex(new FileInputStream(file));
            }
        }
        class Sha1HashProvider extends HashProvider {
            String getHashHex(File file) throws IOException {
                return DigestUtils.sha1Hex(new FileInputStream(file));
            }
        }
    }

Ответ 11

вы можете проверить алгоритм, используемый разработчиками samba/rsync. Я не смотрел на это подробно, но я все время упоминал об этом. по-видимому, неплохо.