У меня есть большой зашифрованный файл (10 ГБ+) на сервере. Мне нужно передать расшифрованный файл клиенту небольшими порциями. Когда клиент делает запрос на кусок байтов (скажем, от 18 до 45), я должен получить произвольный доступ к файлу, прочитать определенные байты, расшифровать его и передать клиенту с помощью ServletResponseStream.
Но поскольку файл зашифрован, мне нужно прочитать файл как блоки по 16 байт, чтобы правильно расшифровать.
Итак, если клиент запрашивает получить от 18 байта до 45, на сервере я должен прочитать файл в блоке, кратном 16 байтам. Поэтому мне нужно получить произвольный доступ к файлу с 16 по 48 байт. Затем расшифровать его. После расшифровки я должен пропустить 2 байта из первого и 3 байта из последнего, чтобы вернуть соответствующий фрагмент данных, запрошенный клиентом.
Вот что я пытаюсь сделать
Настройте начало и конец для зашифрованных файлов
long start = 15; // input from client
long end = 45; // input from client
long skipStart = 0; // need to skip for encrypted file
long skipEnd = 0;
// encrypted files, it must be access in blocks of 16 bytes
if(fileisEncrypted){
skipStart = start % 16; // skip 2 byte at start
skipEnd = 16 - end % 16; // skip 3 byte at end
start = start - skipStart; // start becomes 16
end = end + skipEnd; // end becomes 48
}
Доступ к зашифрованным данным файла от начала до конца
try(final FileChannel channel = FileChannel.open(services.getPhysicalFile(datafile).toPath())){
MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, start, end-start);
// *** No idea how to convert MappedByteBuffer into input stream ***
// InputStream is = (How do I get inputstream for byte 16 to 48 here?)
// the medhod I used earlier to decrypt the all file atonce, now somehow I need the inputstream of specific range
is = new FileEncryptionUtil().getCipherInputStream(is,
EncodeUtil.decodeSeedValue(encryptionKeyRef), AESCipher.DECRYPT_MODE);
// transfering decrypted input stream to servlet response
OutputStream outputStream = response.getOutputStream();
// *** now for chunk transfer, here I also need to
// skip 2 bytes at the start and 3 bytes from the end.
// How to do it? ***/
org.apache.commons.io.IOUtils.copy(is, outputStream)
}
Мне не хватает нескольких шагов в приведенном выше коде. Я знаю, что могу попытаться прочитать байт за байтом и игнорировать 2 байта с первого и 3 байта с последнего. Но я не уверен, что это будет достаточно эффективно. Более того, клиент может запросить большой фрагмент, скажем, с 18-го по 2048-й байт, что потребует чтения и расшифровки почти двух гигабайт данных. Я боюсь, что создание большого массива байтов потребует слишком много памяти.
Как я могу сделать это эффективно, не слишком нагружая серверную обработку или память? Любые идеи?