Получение контрольной суммы MD5 файла в Java

Я хочу использовать Java для получения контрольной суммы файла MD5. Я был очень удивлен, но мне не удалось найти ничего, что показало бы, как получить контрольную сумму MD5 файла.

Как это делается?

Может, это поможет. Вы также можете посмотреть спецификацию, но это потребует больше усилий, поскольку это сложно.

waynecolvin 20.11.2008 06:49

Имейте в виду, что согласно недавнему исследованию «MD5 следует считать криптографически взломанным и непригодным для дальнейшего использования». en.wikipedia.org/wiki/MD5

Zakharia Stanley 03.05.2013 05:06

MD5 больше не считается криптографически безопасным, но его по-прежнему достаточно для проверки целостности файлов и он быстрее, чем SHA.

jiggy 01.07.2013 02:12

@ZakhariaStanley Это вопрос о контрольной сумме.

iPherian 03.05.2017 22:26

Каноническое использование контрольных сумм MD5 для файлов - избежать враждебной замены распределенных файлов. Вот где это небезопасно. Но в сценарии, где враждебные эксплойты не вызывают беспокойства, это идеально подходит.

Keith Tyler 04.10.2018 03:05
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
533
5
444 075
21
Перейти к ответу Данный вопрос помечен как решенный

Ответы 21

В Практические инструкции Real по Java есть пример с использованием класса Дайджест сообщения.

На этой странице также есть примеры с использованием CRC32 и SHA-1.

import java.io.*;
import java.security.MessageDigest;

public class MD5Checksum {

   public 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();
   }

   // see this How-to for a faster way to convert
   // a byte array to a HEX string
   public static String getMD5Checksum(String filename) throws Exception {
       byte[] b = createChecksum(filename);
       String result = "";

       for (int i=0; i < b.length; i++) {
           result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
       }
       return result;
   }

   public static void main(String args[]) {
       try {
           System.out.println(getMD5Checksum("apache-tomcat-5.5.17.exe"));
           // output :
           //  0bb2827c5eacf570b6064e24e0e6653b
           // ref :
           //  http://www.apache.org/dist/
           //          tomcat/tomcat-5/v5.5.17/bin
           //              /apache-tomcat-5.5.17.exe.MD5
           //  0bb2827c5eacf570b6064e24e0e6653b *apache-tomcat-5.5.17.exe
       }
       catch (Exception e) {
           e.printStackTrace();
       }
   }
}

Ага ... все еще в сети спустя 11 лет! :-)

RealHowTo 21.11.2008 05:41

Пример из Real Java-How-To работает отлично, и его легко реализовать.

bakoyaro 27.06.2011 18:30

Цикл чтения немного корявый. read() не вернет ноль, а do/while не совсем подходит.

user207421 16.08.2015 10:43

@EJP Спасибо за своевременный отзыв.

Bill the Lizard 16.08.2015 15:46

байт [] буфер = новый байт [1024]; можем ли мы изменить размер с 1024 на что-нибудь более оптимальное?

Jalpesh 02.06.2016 11:43

Он работает нормально, но я бы рекомендовал подумать о правильном закрытии InputStream при его внедрении в свой проект.

Aleksandr Erokhin 18.10.2016 20:36

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

Dimitri Kopriwa 02.04.2020 10:34

@DimitriKopriwa Это не использует имя файла для вычисления хэша, оно использует содержимое буфера при чтении файла.

Bill the Lizard 03.04.2020 00:57
Ответ принят как подходящий

Есть декоратор входного потока, java.security.DigestInputStream, так что вы можете вычислять дайджест, используя входной поток, как обычно, вместо того, чтобы делать дополнительный проход по данным.

MessageDigest md = MessageDigest.getInstance("MD5");
try (InputStream is = Files.newInputStream(Paths.get("file.txt"));
     DigestInputStream dis = new DigestInputStream(is, md)) 
{
  /* Read decorated stream (dis) to EOF as normal... */
}
byte[] digest = md.digest();

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

Marc Novakowski 06.12.2008 04:51

+1 за потоковую реализацию. @Marc не обязательно должен быть просто HTTP-потоком, потоки java io могут иметь все, что только можно придумать; то есть этот метод будет удобен в самых разных сценариях.

b1nary.atr0phy 09.06.2012 11:24

Пробовал, но возникает эта ошибка Несоответствие типов: невозможно преобразовать из DigestInputStream в FileInputStream, почему это не работает на моей стороне? Я работаю на java 1.6

Al Phaba 17.12.2012 19:25

@AlPhaba Вы объявляли is как InputStream или FileInputStream? Похоже, вы использовали FileInputStream, что могло вызвать эту ошибку.

erickson 17.12.2012 21:16

Можно ли использовать этот подход для нескольких типов дайджестов? Например, если мне нужны и MD5, и SHA1?

carlspring 10.10.2013 18:51

@carlspring В сочетании с входным потоком «тройник» вы могли бы. Написать его самостоятельно или использовать Apache Commons не так уж и сложно. Вот такой вопрос об этом.

erickson 10.10.2013 21:36

@erickson, я вообще-то тут задал вопрос: stackoverflow.com/questions/19300774/…. Если у вас есть время, может, вы могли бы проиллюстрировать это для меня?

carlspring 10.10.2013 21:42

@barwnikk Он отлично работает в Java 8. MethodNotFound не является исключением из стандартной Java; возможно вы говорите об ошибке компилятора? В любом случае, если это не сработает для вас, это проблема локальной конфигурации или проблема с другим кодом.

erickson 23.06.2014 22:45

@barwnikk Опять же, это проблема вашей локальной конфигурации. Это действительный код Java 7 и Java 8. Если вы застряли с инструментами из 2006 года, вам придется адаптироваться.

erickson 07.07.2014 19:41

@erickson Вы не обновляете объект MessageDigest содержимым файла. Rt? Этот код всегда будет печатать один и тот же дайджест.

sunil 31.10.2014 11:16

@sunil Нет. MessageDigest обновляет объект DigestInputStream со всеми данными в файле. Он вернет тот же дайджест, только если содержимое файла идентично (или есть конфликт хешей, что практически невозможно, если кто-то намеренно не воспользуется слабостью MD5).

erickson 01.11.2014 06:24

@erickson Ты был прав, Эриксон. Я забыл прочитать содержимое, чтобы обновить объект MessageDigest. Я обновил ваш ответ этим изменением.

sunil 02.11.2014 09:26

@erickson Мне было интересно, почему эта функция продолжает возвращать один и тот же хеш, но похоже, что ваше последнее изменение (3 ноября) снова нарушило код. Часть «while (dis.read ()! = -1); dis.close ();» должен быть выполнен, чтобы вернуть правильный md5.

Symen Timmermans 21.10.2015 13:15

@SymenTimmermans Спасибо, что заметили это. Моя редакция должна это исправить.

erickson 21.10.2015 19:02

IMO, в этом случае нет необходимости закрывать is, так как закрытие dis автоматически закрывает dis. Итак, вы можете переместить InputStream is = Files.newInputStream(Paths.get("file.txt")) из try (...) (т.е. вот так: MessageDigest md = MessageDigest.getInstance("MD5"); InputStream is = Files.newInputStream(Paths.get("file.txt")); try (DigestInputStream dis = new DigestInputStream(is, md)) {...}). Хотя я не уверен насчет стиля кодирования (возможно, некоторые рекомендации по стилю требуют, чтобы и is, и dis находились внутри try (...), но это не требует логики программы как таковой).

Sasha 16.06.2016 21:24

Или вот так: MessageDigest md = MessageDigest.getInstance("MD5"); try (DigestInputStream is = new DigestInputStream(Files.newInputStream(Paths.get("file.txt")‌​), md)) {...} byte[] digest = md.digest();.

Sasha 16.06.2016 21:28

@Sasha Что делать, если при создании потока дайджеста возникает исключение? Тогда поток ввода файла не будет своевременно закрыт. С другой стороны, какой вред может быть в явном принудительном закрытии входного потока базового файла при выходе из блока try? Я не вижу никакой ценности в этой микрооптимизации.

erickson 17.06.2016 08:26

@erickson, "что, если создание потока дайджеста вызовет исключение" - AFAIK, не может. «Я не вижу никакой ценности в этой микрооптимизации» - вы правы, в этом нет никакой ценности, это просто вопрос стиля кода. (Я просто хотел указать, что закрывать базовый поток не обязательно, поскольку он автоматически закрывается потоком-оболочкой - это может быть неочевидно для новичков в Java.)

Sasha 17.06.2016 12:49

Но какая переменная в итоге содержит хеш MD-5?

gstackoverflow 20.11.2017 11:19

@gstackoverflow Переменная digest в конце.

erickson 20.11.2017 19:14

Он всегда возвращает один и тот же результат.

Anmol Singh Jaggi 24.05.2019 10:08

@AnmolSinghJaggi Фактически вы должны прочитать весь поток внутри блока try. Если ваш код не работает, вы можете открыть свой вопрос с помощью минимальный воспроизводимый пример, чтобы узнать, где находится ваша ошибка.

erickson 24.05.2019 15:37

Ааа теперь вижу .. Пропустил, так как очень торопился. Вероятно, вам также следует заполнить этот код.

Anmol Singh Jaggi 24.05.2019 15:59

@AnmolSinghJaggi Что ж, идея шаблона Decorator заключается в том, что любой код, который работает с InputStream, будет работать с этим расширением и вычислять дайджест как побочный эффект любой обработки, которую вы обычно выполняете (например, загрузка файла, его анализ, так далее.). Я не знаю, какую обработку будут использовать люди, поэтому я не могу выполнять их (всю) работу за них.

erickson 24.05.2019 16:04

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

Wayne Wei 09.06.2020 13:17

@WayneWei Нет. MD5-хеш - это алгоритм с постоянным пространством. Он хранит только 16 байтов состояния для вычислений. Реализация может использовать внутри 64-байтовый буфер блока.

erickson 09.06.2020 18:33

Недавно мне пришлось сделать это только для динамической строки, MessageDigest может представлять хеш разными способами. Чтобы получить подпись файла, как при использовании команды md5sum, мне пришлось сделать что-то вроде этого:

try {
   String s = "TEST STRING";
   MessageDigest md5 = MessageDigest.getInstance("MD5");
   md5.update(s.getBytes(),0,s.length());
   String signature = new BigInteger(1,md5.digest()).toString(16);
   System.out.println("Signature: "+signature);

} catch (final NoSuchAlgorithmException e) {
   e.printStackTrace();
}

Это, очевидно, не отвечает на ваш вопрос о том, как это сделать специально для файла, приведенный выше ответ прекрасно справляется с этим. Я просто потратил много времени на то, чтобы сумма выглядела так, как ее отображает большинство приложений, и подумал, что вы можете столкнуться с той же проблемой.

Подпись представляет собой дайджест в шестнадцатеричном формате. Я тоже обнаружил, что шестнадцатеричное представление работает там, где, как вы говорите, другие представления не работают. Спасибо, что разместили это.

amit 12.10.2009 13:33

Это хорошо, но .toString(16) отбрасывает ведущие нули. String.format("%032x", ...) может быть лучше.

Harold 10.06.2020 18:37

Используйте DigestUtils из библиотеки Кодек Apache Commons:

try (InputStream is = Files.newInputStream(Paths.get("file.zip"))) {
    String md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(is);
}

У меня не работает в моем коде Android, я получаю эту ошибку ... java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString в org.apache.commons.codec.digest.DigestUtils.md5Hex (DigestUti‌ ls.java:215)

JPM 02.05.2012 01:03

@JPM Предположим, вы уже загрузили и поместили commons-codec.jar в свой путь к классам?

Leif Gruenwoldt 02.05.2012 01:07

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

JPM 02.05.2012 01:08

У меня была такая же проблема, но она исправлена ​​этим кодом `FileInputStream fis = new FileInputStream (new File (filePath)); байтовые данные [] = org.apache.commons.codec.digest.DigestUtils.md5 (fis); char md5Chars [] = Hex.encodeHex (данные); Строка md5 = String.valueOf (md5Chars); `

Dmitry_L 17.07.2013 14:45

Хороший! Для новых проектов я всегда дважды думаю, прежде чем добавлять новую зависимость, но для существующего проекта мне просто нужно проверить, существует ли уже библиотека, чтобы использовать ее. +1

OscarRyz 01.08.2013 00:45

Очень хорошо! Также работает в MATLAB ... Просто прочтите файл 'fis' и используйте 'md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex (fis);'

Tom Anderson 21.02.2016 09:32

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

Arturas M 01.10.2016 20:29

Если вы используете ANT для сборки, это очень просто. Добавьте в свой build.xml следующее:

<checksum file = "${jarFile}" todir = "${toDir}"/>

Где jarFile - это JAR, для которого вы хотите сгенерировать MD5, а toDir - это каталог, в который вы хотите поместить файл MD5.

Больше информации здесь.

public static String MD5Hash(String toHash) throws RuntimeException {
   try{
       return String.format("%032x", // produces lower case 32 char wide hexa left-padded with 0
      new BigInteger(1, // handles large POSITIVE numbers 
           MessageDigest.getInstance("MD5").digest(toHash.getBytes())));
   }
   catch (NoSuchAlgorithmException e) {
      // do whatever seems relevant
   }
}

Мы использовали код, похожий на код, приведенный выше в предыдущем сообщении, используя

...
String signature = new BigInteger(1,md5.digest()).toString(16);
...

Однако будьте осторожны при использовании здесь BigInteger.toString(), так как он обрезает ведущие нули ... (например, попробуйте s = "27", контрольная сумма должна быть "02e74f10e0327ad868d138f2b4fdd6f0")

Я поддерживаю предложение использовать кодек Apache Commons, я заменил на него наш собственный код.

Вау, я изучал проблему, при которой материал MD5 работал отлично для всего, за исключением того, что файл давал нам только 31 шестнадцатеричный вывод и не давал md5checksums. усечение ведущих нулей - огромная боль ... Спасибо за вашу заметку.

Mike 01.03.2012 22:11

API com.google.common.hash предлагает:

  • Единый удобный API для всех хэш-функций
  • Seedable 32- и 128-битные реализации murmur3
  • md5 (), sha1 (), sha256 (), sha512 (), измените только одну строку кода, чтобы переключаться между ними, и бормочите.
  • goodFastHash (int биты), когда вам все равно, какой алгоритм вы используете
  • Общие утилиты для экземпляров HashCode, такие как combOrdered / combUnordered.

Прочтите руководство пользователя (Объяснение ввода-вывода, Объяснение хеширования).

Для вашего варианта использования Files.hash() вычисляет и возвращает значение дайджеста для файла.

Например, расчет дайджеста (измените SHA-1 на MD5, чтобы получить дайджест MD5)

HashCode hc = Files.asByteSource(file).hash(Hashing.sha1());
"SHA-1: " + hc.toString();

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

Для долгосрочной защиты с помощью хэшей Схема подписи Меркла добавляет к безопасности, и Исследовательская группа Post Quantum Cryptography, спонсируемая Европейской Комиссией, рекомендовала использовать эту криптографию для долгосрочной защиты от квантовых компьютеров (ссылка).

Обратите внимание, что имеет более высокую частоту конфликтов, чем другие.

Какая часть Files.hash, как указано выше, не охватывает Files.hash?

oluies 26.02.2015 01:57

Files.hash() отмечен как устаревший, рекомендуемый способ: Files.asByteSource(file).hash(Hashing.sha1())

erkfel 15.12.2017 23:53

А по состоянию на январь 2018 года Hashing.sha1() помечен как устаревший. Вместо этого рекомендуется использовать функцию Hashing.sha256(). источник

MagicLegend 20.03.2018 14:28

Другая реализация: Быстрая реализация MD5 на Java

String hash = MD5.asHex(MD5.getHash(new File(filename)));

Я не могу найти метод MD5.asHex() в JDK 1.8.0 242.

cbaldan 12.02.2020 19:12

Гуава теперь предоставляет новый согласованный API хеширования, который намного удобнее для пользователя, чем различные API хеширования, представленные в JDK. См. Объяснение хеширования. Для файла вы можете легко получить сумму MD5, CRC32 (с версией 14.0+) или многие другие хэши:

HashCode md5 = Files.hash(file, Hashing.md5());
byte[] md5Bytes = md5.asBytes();
String md5Hex = md5.toString();

HashCode crc32 = Files.hash(file, Hashing.crc32());
int crc32Int = crc32.asInt();

// the Checksum API returns a long, but it's padded with 0s for 32-bit CRC
// this is the value you would get if using that API directly
long checksumResult = crc32.padToLong();
public static void main(String[] args) throws Exception {
    MessageDigest md = MessageDigest.getInstance("MD5");
    FileInputStream fis = new FileInputStream("c:\\apache\\cxf.jar");

    byte[] dataBytes = new byte[1024];

    int nread = 0;
    while ((nread = fis.read(dataBytes)) != -1) {
        md.update(dataBytes, 0, nread);
    };
    byte[] mdbytes = md.digest();
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < mdbytes.length; i++) {
        sb.append(Integer.toString((mdbytes[i] & 0xff) + 0x100, 16).substring(1));
    }
    System.out.println("Digest(in hex format):: " + sb.toString());
}

Или вы можете получить дополнительную информацию http://www.asjava.com/core-java/java-md5-example/

ЭТОТ ОТВЕТ хорош, я потратил 12 часов, прежде чем использовать этот ответ, чтобы достичь того, чего я хочу огромное спасибо :)

b devloper 05.03.2021 15:53

В порядке. Пришлось добавить. Однострочная реализация для тех, кто уже имеет зависимость Spring и Apache Commons или планирует ее добавить:

DigestUtils.md5DigestAsHex(FileUtils.readFileToByteArray(file))

Вариант только для общего пользования и Apache (кредит @duleshi):

DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))

Надеюсь, это кому-то поможет.

Это DigestUtils.md5Hex(FileUtils.readFileToByteArray(file))

duleshi 07.08.2015 09:34

Решение, основанное на сообществе Дэвида Онтера, лучше, потому что оно не считывает весь файл в память.

Fran Marzoa 18.03.2018 04:12

По крайней мере, для Spring 5 у вас есть DigestUtils.md5Digest(InputStream inputStream) для вычисления дайджеста MD5 и DigestUtils.md5DigestAsHex(InputStream inputStream) для шестнадцатеричного строкового представления методов дайджеста MD5 без чтения всего файла в память.

Mike Shauneu 20.09.2018 05:58

Стандартный способ среды выполнения Java:

public String checksum(File file) {
  try {
    InputStream fin = new FileInputStream(file);
    java.security.MessageDigest md5er =
        MessageDigest.getInstance("MD5");
    byte[] buffer = new byte[1024];
    int read;
    do {
      read = fin.read(buffer);
      if (read > 0)
        md5er.update(buffer, 0, read);
    } while (read != -1);
    fin.close();
    byte[] digest = md5er.digest();
    if (digest == null)
      return null;
    String strDigest = "0x";
    for (int i = 0; i < digest.length; i++) {
      strDigest += Integer.toString((digest[i] & 0xff) 
                + 0x100, 16).substring(1).toUpperCase();
    }
    return strDigest;
  } catch (Exception e) {
    return null;
  }
}

Результат аналогичен утилите linux md5sum.

Google guava предоставляет новый API. Найдите тот, что ниже:

public static HashCode hash(File file,
            HashFunction hashFunction)
                     throws IOException

Computes the hash code of the file using hashFunction.

Parameters:
    file - the file to read
    hashFunction - the hash function to use to hash the data
Returns:
    the HashCode of all of the bytes in the file
Throws:
    IOException - if an I/O error occurs
Since:
    12.0
public static String getMd5OfFile(String filePath)
{
    String returnVal = "";
    try 
    {
        InputStream   input   = new FileInputStream(filePath); 
        byte[]        buffer  = new byte[1024];
        MessageDigest md5Hash = MessageDigest.getInstance("MD5");
        int           numRead = 0;
        while (numRead != -1)
        {
            numRead = input.read(buffer);
            if (numRead > 0)
            {
                md5Hash.update(buffer, 0, numRead);
            }
        }
        input.close();

        byte [] md5Bytes = md5Hash.digest();
        for (int i=0; i < md5Bytes.length; i++)
        {
            returnVal += Integer.toString( ( md5Bytes[i] & 0xff ) + 0x100, 16).substring( 1 );
        }
    } 
    catch(Throwable t) {t.printStackTrace();}
    return returnVal.toUpperCase();
}

Использование nio2 (Java 7+) и без внешних библиотек:

byte[] b = Files.readAllBytes(Paths.get("/path/to/file"));
byte[] hash = MessageDigest.getInstance("MD5").digest(b);

Чтобы сравнить результат с ожидаемой контрольной суммой:

String expected = "2252290BC44BEAD16AA1BF89948472E8";
String actual = DatatypeConverter.printHexBinary(hash);
System.out.println(expected.equalsIgnoreCase(actual) ? "MATCH" : "NO MATCH");

@Arash да абсолютно - спасибо. Я перепутал класс JDK Files и класс Guava.

assylias 23.05.2016 13:30

Мне это решение нравится больше, чем решение Эриксона, так как оно может быть обернуто опциями для использования программирования в чисто функциональном стиле.

Gabriel Hernandez 24.09.2018 19:19

Для большого файла это будет использовать много памяти, так как весь файл читается и затем передается в дайджест вместо чтения фрагментов и «переваривания» их по мере чтения.

bernie 03.12.2018 20:00

Простой подход без сторонних библиотек с использованием Java 7

String path = "your complete file path";
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(Files.readAllBytes(Paths.get(path)));
byte[] digest = md.digest();

Если вам нужно распечатать этот массив байтов. Используйте как показано ниже

System.out.println(Arrays.toString(digest));

Если вам нужна шестнадцатеричная строка из этого дайджеста. Используйте как показано ниже

String digestInHex = DatatypeConverter.printHexBinary(digest).toUpperCase();
System.out.println(digestInHex);

где DatatypeConverter - это javax.xml.bind.DatatypeConverter

Почему именно toUpperCase?

EdgeCaseBerg 26.12.2015 16:53

@edgecaseberg только для шестнадцатеричной строки выглядит хорошо при печати на консоли

sunil 26.12.2015 20:47

Я обнаружил, что мне нужно использовать toLowerCase () вместо toUpperCase ().

Splendor 24.02.2016 20:59

Очень быстрый и чистый Java-метод, не использующий внешние библиотеки:

(Просто замените MD5 на SHA-1, SHA-256, SHA-384 или SHA-512, если они вам нужны)

public String calcMD5() throws Exception{
        byte[] buffer = new byte[8192];
        MessageDigest md = MessageDigest.getInstance("MD5");

        DigestInputStream dis = new DigestInputStream(new FileInputStream(new File("Path to file")), md);
        try {
            while (dis.read(buffer) != -1);
        }finally{
            dis.close();
        }

        byte[] bytes = md.digest();

        // bytesToHex-method
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }

        return new String(hexChars);
}
String checksum = DigestUtils.md5Hex(new FileInputStream(filePath));

Вот простая функция, которая обтекает код Сунила и принимает в качестве параметра файл. Функция не требует внешних библиотек, но требует Java 7.

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.xml.bind.DatatypeConverter;

public class Checksum {

    /**
     * Generates an MD5 checksum as a String.
     * @param file The file that is being checksummed.
     * @return Hex string of the checksum value.
     * @throws NoSuchAlgorithmException
     * @throws IOException
     */
    public static String generate(File file) throws NoSuchAlgorithmException,IOException {

        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        messageDigest.update(Files.readAllBytes(file.toPath()));
        byte[] hash = messageDigest.digest();

        return DatatypeConverter.printHexBinary(hash).toUpperCase();
    }

    public static void main(String argv[]) throws NoSuchAlgorithmException, IOException {
        File file = new File("/Users/foo.bar/Documents/file.jar");          
        String hex = Checksum.generate(file);
        System.out.printf("hex=%s\n", hex);            
    }


}

Пример вывода:

hex=B117DD0C3CBBD009AC4EF65B6D75C97B

Вот удобный вариант, который использует InputStream.transferTo() из Java 9 и OutputStream.nullOutputStream() из Java 11. Он не требует внешних библиотек и не требует загрузки всего файла в память.

public static String hashFile(String algorithm, File f) throws IOException, NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance(algorithm);

    try(BufferedInputStream in = new BufferedInputStream((new FileInputStream(f)));
        DigestOutputStream out = new DigestOutputStream(OutputStream.nullOutputStream(), md)) {
        in.transferTo(out);
    }

    String fx = "%0" + (md.getDigestLength()*2) + "x";
    return String.format(fx, new BigInteger(1, md.digest()));
}

и

hashFile("SHA-512", Path.of("src", "test", "resources", "some.txt").toFile());

возвращается

"e30fa2784ba15be37833d569280e2163c6f106506dfb9b07dde67a24bfb90da65c661110cf2c5c6f71185754ee5ae3fd83a5465c92f72abd888b03187229da29"

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