Java: как на лету вычислить дайджест sha1 для сохраняемого потока? - PullRequest
0 голосов
/ 04 сентября 2018

У меня есть сервлет, написанный на Java, который принимает отправленный файл в форме нескольких частей, который необходимо сохранить в MongoDb / GridFS. У меня уже есть код, работающий для этого.

Вот фрагмент кода, который показывает, как это делается с помощью пакета org.apache.commons.fileupload. Он почти не потребляет память, поскольку не хранит слишком много данных в памяти.

        ServletFileUpload upload = new ServletFileUpload();
        FileItemIterator iter = upload.getItemIterator(req);
        while (iter.hasNext()) {
            FileItemStream item = iter.next();
            String name = item.getFieldName();
            InputStream stream = item.openStream();
            if (item.isFormField()) {
                toProcess.put(name, Streams.asString(stream));
            } else {
                String fileName = item.getName();
                String contentType = item.getHeaders().getHeader("Content-Type");
                GridFSUploadOptions options = new GridFSUploadOptions()
                        // .chunkSizeBytes(358400)
                        .metadata(new Document("content_type", contentType));
                ObjectId fileId = gridFSFilesBucket.uploadFromStream(fileName, stream, options);
                fileIds.add(fileId);
                fileNames.add(fileName);
            }

Мне также нужно вычислить значения хэша sha1 для всех файлов. Apache digestutils может быть использован для этого. У него есть метод, который может вычислять sha1 в потоке:

https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/DigestUtils.html#sha1-java.io.InputStream-

Моя проблема в том, что этот метод полностью использует поток. Мне нужно разделить входной поток на две части. Введите одну часть в расчет SHA-1, а другую - в корзину GridFS.

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

Я просто не знаю, как начать писать такой канал.

1 Ответ

0 голосов
/ 04 сентября 2018

Вы можете использовать класс Java API DigestInputStream

Как объясняет Javadoc,

Прозрачный поток, который обновляет связанный дайджест сообщения, используя биты, идущие через поток.

Для завершения дайджеста сообщения вычисления, вызовите один из методов дайджеста в связанном сообщении дайджест после ваших звонков на чтение одного из этого входного потока дайджеста методы.

В своем коде вы можете сделать это:

InputStream stream = item.openStream();
MessageDigest digest = MessageDigest.getInstance("SHA-256");
stream = new DigestInputStream(stream, digest);

И в конце вы можете получить дайджест:

byte[] hash = digest.digest();
...