Получить из ByteBuffer в byte[] не пишет в byte[]

Я последовательно читаю блоки BLOCKSIZE (например, 512) байтов из SocketChannel в ByteBuffer. Затем я хотел бы добавить содержимое ByteBuffer к байту [] и перейти к следующему раунду. Результатом будет byte[], содержащий все байты, прочитанные из SocketChannel.

Теперь System.arraycopy(...) работает как положено. Но когда я использую get(result, offset, length) ByteBuffer, ничего не пишется. Значения результирующего массива остаются обнуленными.

Это почему?

  public final static int BLOCKSIZE = 512;

  public byte[] getReceivedData() {
    int offset = 0, read;
    byte[] result = {};
    ByteBuffer buffer = ByteBuffer.allocate(BLOCKSIZE);
    try {
      while (true) {
        read = _socketChannel.read(buffer);
        if (read < 1) {
          // Nothing was read.
          break;
        }

        // Enlarge result so we can append the bytes we just read.
        result = Arrays.copyOf(result, result.length + read);

        // This works as expected.
        System.arraycopy(buffer.array(), 0, result, offset * BLOCKSIZE, read);

        // With this, however, nothing is written to result. Why?
        buffer.get(result, offset * BLOCKSIZE, read);

        if (read < BLOCKSIZE) {
          // Nothing left to read from _socketChannel.
          break;
        }

        buffer.clear();
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return result;
  }

ИЗМЕНИТЬ:

Я заметил, что offset++ тоже отсутствует. Поэтому, если на канале больше BLOCKSIZE байт, все запутается...

В любом случае, ByteArrayOutputStream действительно все упрощает, поэтому я решил использовать его.

Рабочий код:

  public byte[] getReceivedData() {
    int read;
    ByteArrayOutputStream result = new ByteArrayOutputStream();
    ByteBuffer buffer = ByteBuffer.allocate(BLOCKSIZE);
    try {
      while (true) {
        buffer.clear();
        read = _socketChannel.read(buffer);
        if (read < 1) {
          break;
        }
        result.write(buffer.array(), 0, read);
        if (read < BLOCKSIZE) {
          break;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return result.toByteArray();
  }

person riha    schedule 22.03.2012    source источник


Ответы (2)


Вам нужно flip() буфер перед get() и compact() после него.

Если read == -1 нужно не только выйти из цикла, но и закрыть канал.

person user207421    schedule 22.03.2012
comment
flip() сделал свое дело, спасибо. Я думаю, что compact() не требуется. После get()обработки всего из буфера нечего сжимать, и он все равно clear()обрабатывается на каждой итерации. Также спасибо за подсказку закрыть канал. Я знаю, что каналы остаются открытыми, и это предназначено. Клиенты могут отправлять новые данные в любое время. - person riha; 22.03.2012
comment
@riha Неправильно. Ни один клиент никогда не отправит вам больше данных после того, как вы получите -1. Это конец потока на канале, и это означает, что партнер закрыл соединение или, по крайней мере, закрыл его для вывода. Закрой его. - person user207421; 23.03.2012
comment
Хм, хорошо, тогда он действительно должен быть закрыт и с моей стороны. Хотя в моем случае такого быть не должно, но это уже другая история. Еще раз спасибо. - person riha; 23.03.2012

Ваш массив результатов имеет длину 0 и не может содержать никакой информации. Массивы байтов не растут, и вы не можете добавлять содержимое буферов. Используйте java.io.ByteArrayOutputStream для накопления результата.

person Alexei Kaigorodov    schedule 22.03.2012
comment
Неправильный. Его результирующий массив переназначается внутри цикла. - person user207421; 22.03.2012
comment
Хороший намек на ByteArrayOutputStream. Это делает вещи намного проще. - person riha; 22.03.2012