Как вы получаете последовательные срезы из ByteBuffer?


У меня есть ByteBuffer , который содержит большой файл (100 МБ):

    java.nio.ByteBuffer byteBuffer = ByteBuffer.wrap(multipartFile.getBytes());
    writeChannel.write(byteBuffer);
    writeChannel.closeFinally();
Я могу только легально записать 1 МБ в writeChannel одновременно.

Как я могу нарезать содержимое ByteBuffer и записать только 1 МБ среза за один раз в writeChannel?

2 5

2 ответа:

Вы можете использовать ByteBuffer#slice() чтобы получить дубликат представления вашего базового экземпляра ByteBuffer, затем переместите позицию вдоль, чтобы открыть скользящее окно содержимого. Кроме того, вы можете просто сделать то же самое с вашим базовым буфером, если вам не нужно предоставлять его другим потребителям.

Вы можете изменить начальную позицию вашего представления контента с помощью метода с одним аргументом Buffer#position(int) , а также изменить конечную позицию вашего представления с помощью Buffer#limit(int). До тех пор, пока вы будете внимательны, чтобы не толкать посмотреть за пределы базового буфера можно следующим образом:

final ByteBuffer view = base.slice();
for (int start = base.position(), end = base.limit(), stride = 1000000;
     start != end;
     start = view.limit())
  consume(view.position(start)
              .limit(start + Math.min(end - start, stride)));

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

Я оставил его таким образом, чтобы сохранить основную структуру цикла.

Насколько мне известно, write () на writeChannel (который, как я предположил, имеет тип SocketChannel) будет "пытаться записать до r байт в канал, где r-количество байт, оставшихся в буфере, то есть dst.remaining (), в данный момент этот метод вызывается". (согласно Этому)

Описание ByteBuffer.remaining () говорит, что этот метод "вернет количество элементов между текущей позицией и пределом."

Итак, мой предположение заключается не в том, что вы не можете написать весь ByteBuffer, а в том, что ваш код должен вызвать flip() на объекте ByteBuffer, чтобы он стал:

java.nio.ByteBuffer byteBuffer = ByteBuffer.wrap(multipartFile.getBytes());
byteBuffer.flip();
writeChannel.write(byteBuffer);
writeChannel.closeFinally();

Как сказано в буфере .flip () : "после последовательности операций чтения канала или put вызовите этот метод для подготовки к последовательности операций записи канала или относительного get"