#java #stream #zip #checksum
#java #поток #zip #контрольная сумма
Вопрос:
Мне нужно определить контрольную сумму .zip
файла перед его загрузкой куда-либо, чтобы обеспечить целостность файла.
В настоящее время у меня есть что-то вроде следующего:
for (File file : zipCandidates) {
InputStream fileInputStream = new BufferedInputStream(new FileInputStream(file));
ZipUtils.addDataToZip(zipStream, fileInputStream, file.getName());
boolean deleted = file.delete();
if (!deleted) {
log.error("Failed to delete temporary file {} : {}", file.getName(), file.getAbsolutePath());
}
}
zipStream.close();
// checksum and filesize
long fileSize = zipFile.length();
InputStream fileInputStream = FileUtils.openInputStream(zipFile);
BufferedInputStream bufferedFileInputStream = new BufferedInputStream(fileInputStream);
String checksum = DigestUtils.md5Hex(bufferedFileInputStream);
bufferedFileInputStream.close();
// upload
fileInputStream = FileUtils.openInputStream(zipFile);
bufferedFileInputStream = new BufferedInputStream(fileInputStream);
val writer = writerFactory.createWriter(blobName, fileSize, checksum);
writer.write(bufferedFileInputStream);
bufferedFileInputStream.close();
Излишне говорить, что это очень неэффективно, поскольку мне приходится .zip
дважды читать каждый файл, чтобы определить его контрольную сумму перед его загрузкой.
Есть ли какой-нибудь способ объединить мои ZipOutputStream
above и a DigestOutputstream
, чтобы я мог просто обновить свою контрольную сумму при записи zip-файла? К сожалению, поскольку выходной поток должен быть a ZipOutputStream
, я не могу просто украсить его (т.Е. new DigestOutputStream(zipStream, digest)
).
Ответ №1:
К сожалению, поскольку выходной поток должен быть a
ZipOutputStream
, я не могу просто украсить его (т.Е.new DigestOutputStream(zipStream, digest)
).
Вы бы все равно этого не хотели, потому что вы хотите переварить результат операции архивирования, поэтому вам нужно обернуть DigestOutputStream
с ZipOutputStream
помощью, то есть другим способом:
try (ZipOutputStream zipStream = new ZipOutputStream(
new DigestOutputStream(
new FileOutputStream(zipFile),
digest))) {
// code adding zip entries here
}
String checksum = Hex.encodeHexString(digest.digest());
Обратите внимание на использование try-with-resources, чтобы убедиться, что ваш ZipOutputStream
файл всегда закрыт правильно.
Комментарии:
1. Я понимаю. Я предполагаю, что я неправильно истолковал, как
DigestOutputStream
функционирует — я не понимал, что потокdigest
будет изменен потоком и может быть прочитан позже. Спасибо.
Ответ №2:
Вы, конечно, можете создать собственный выходной поток, который обертывает два выходных потока (в вашем конкретном случае один будет вашим ZipOutputStream, а другой — вашим DigestOutputStream). Ваша новая реализация потока вывода будет записывать каждый байт, который он получает, в оба обернутых потока.
Этот вариант использования достаточно распространен, поэтому вы, вероятно, найдете версию с открытым исходным кодом, которая будет соответствовать вашим потребностям (например, эта из apache commons).