Как рассчитать контрольную сумму md5 для каталога с Java или Groovy? - PullRequest
4 голосов
/ 10 июня 2010

Я хочу использовать java или groovy для получения контрольной суммы md5 полного каталога.

Мне нужно скопировать каталоги для источника в цель, контрольной суммы источника и цели и после удаления исходных каталогов.

Я нашел этот скрипт для файлов, но как сделать то же самое с каталогами?

import java.security.MessageDigest

def generateMD5(final file) {
    MessageDigest digest = MessageDigest.getInstance("MD5")
    file.withInputStream(){ is ->
        byte[] buffer = new byte[8192]
        int read = 0
        while( (read = is.read(buffer)) > 0) {
            digest.update(buffer, 0, read);
        }
    }
    byte[] md5sum = digest.digest()
    BigInteger bigInt = new BigInteger(1, md5sum)

    return bigInt.toString(16).padLeft(32, '0')
}

Есть ли лучший подход?

Ответы [ 5 ]

9 голосов
/ 19 марта 2013

У меня было такое же требование, и я выбрал «хэш каталога» в качестве хэша MD5 объединенных потоков всех (не-каталогов) файлов в каталоге. Как Крозин упомянул в комментариях к аналогичному вопросу , вы можете использовать SequenceInputStream, чтобы действовать как поток, объединяющий нагрузку других потоков. Я использую Кодек Apache Commons для алгоритма MD5.

По сути, вы выполняете поиск по дереву каталогов, добавляя FileInputStream экземпляров к Vector для файлов, не относящихся к каталогам. Vector затем имеет удобный метод elements() для предоставления Enumeration, который SequenceInputStream должен пройти через цикл. Для алгоритма MD5 это просто выглядит как один InputStream.

Суть в том, что вам нужно, чтобы файлы были представлены в одном и том же порядке каждый раз, чтобы хэш был одинаковым с одинаковыми входными данными. Метод listFiles() в File не гарантирует порядок, поэтому я сортирую по имени файла.

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

Соответствующий базовый код приведен ниже. (Очевидно, это может быть «закалено».)

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

import java.io.*;
import java.util.*;

public String calcMD5HashForDir(File dirToHash, boolean includeHiddenFiles) {

    assert (dirToHash.isDirectory());
    Vector<FileInputStream> fileStreams = new Vector<FileInputStream>();

    System.out.println("Found files for hashing:");
    collectInputStreams(dirToHash, fileStreams, includeHiddenFiles);

    SequenceInputStream seqStream = 
            new SequenceInputStream(fileStreams.elements());

    try {
        String md5Hash = DigestUtils.md5Hex(seqStream);
        seqStream.close();
        return md5Hash;
    }
    catch (IOException e) {
        throw new RuntimeException("Error reading files to hash in "
                                   + dirToHash.getAbsolutePath(), e);
    }

}

private void collectInputStreams(File dir,
                                 List<FileInputStream> foundStreams,
                                 boolean includeHiddenFiles) {

    File[] fileList = dir.listFiles();        
    Arrays.sort(fileList,               // Need in reproducible order
                new Comparator<File>() {
                    public int compare(File f1, File f2) {                       
                        return f1.getName().compareTo(f2.getName());
                    }
                });

    for (File f : fileList) {
        if (!includeHiddenFiles && f.getName().startsWith(".")) {
            // Skip it
        }
        else if (f.isDirectory()) {
            collectInputStreams(f, foundStreams, includeHiddenFiles);
        }
        else {
            try {
                System.out.println("\t" + f.getAbsolutePath());
                foundStreams.add(new FileInputStream(f));
            }
            catch (FileNotFoundException e) {
                throw new AssertionError(e.getMessage()
                            + ": file should never not be found!");
            }
        }
    }

}
4 голосов
/ 11 июня 2010

Я сделал функцию для вычисления контрольной суммы MD5 в каталоге:

Сначала я использую FastMD5: http://www.twmacinta.com/myjava/fast_md5.php

Вот мой код:

  def MD5HashDirectory(String fileDir) {
    MD5 md5 = new MD5();
    new File(fileDir).eachFileRecurse{ file ->
      if (file.isFile()) {
        String hashFile = MD5.asHex(MD5.getHash(new File(file.path)));
        md5.Update(hashFile, null);
      }

    }
    String hashFolder = md5.asHex();
    return hashFolder
  }
2 голосов
/ 24 октября 2017

Основано на ответе Stuart Rossiter , но чистый код и скрытые файлы обрабатываются правильно:

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

import java.io.*;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Vector;

public class Hashing
{
    public static String hashDirectory(String directoryPath, boolean includeHiddenFiles) throws IOException
    {
        File directory = new File(directoryPath);

        if (!directory.isDirectory())
        {
            throw new IllegalArgumentException("Not a directory");
        }

        Vector<FileInputStream> fileStreams = new Vector<>();
        collectFiles(directory, fileStreams, includeHiddenFiles);

        try (SequenceInputStream sequenceInputStream = new SequenceInputStream(fileStreams.elements()))
        {
            return DigestUtils.md5Hex(sequenceInputStream);
        }
    }

    private static void collectFiles(File directory,
                                     List<FileInputStream> fileInputStreams,
                                     boolean includeHiddenFiles) throws IOException
    {
        File[] files = directory.listFiles();

        if (files != null)
        {
            Arrays.sort(files, Comparator.comparing(File::getName));

            for (File file : files)
            {
                if (includeHiddenFiles || !Files.isHidden(file.toPath()))
                {
                    if (file.isDirectory())
                    {
                        collectFiles(file, fileInputStreams, includeHiddenFiles);
                    } else
                    {
                        fileInputStreams.add(new FileInputStream(file));
                    }
                }
            }
        }
    }
}
2 голосов
/ 20 октября 2012

HashCopy - это Java-приложение. Он может генерировать и проверять MD5 и SHA для одного файла или каталога рекурсивно. Я не уверен, что у него есть API. Его можно загрузить с www.jdxsoftware.org.

0 голосов
/ 10 июня 2010

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

...